JavaFX: How can I detect end of rendering in TitledPane?

146 Views Asked by At

This is the background for my question:

I have a GUI with an accordion with many TitledPanes, and each Titledpane contains a spreadsheetView from the controlsFX package. There is a search-function in the code, where a Titledpane is opened and a specific cell in the spreadsheetView is opened for text input using the edit method of the spreadsheetcell type.

If the TitledPane is already open, this works fine, but if it must open first then the call of the edit-method fails. (The program is actually written in scalafx, but I don't think that matters here because scalafx is just a wrapper of javaFX and calls all the javaFX methods.) Someone from the scalafx user group found out, that when I put in a wait time of 350ms (The animation time of the TitledPane is 300ms) then the call of 'edit' on the cell succeeds. He thought that the call fails, when the rendering of the content of the TitledPane is not complete. This is also true when I turn the animation for the TitledPane off. In this case, it is sufficient to wait for 50ms, which does not work when animation is on.

Anyway - I am concerned about just waiting 350ms and hoping that this will always work. Which brings me back to the question: How can I tell that the rendering inside the TitledPane (or the spreadsheetView?) is complete so that I can safely call my edit method on the spreadsheetView?

2

There are 2 best solutions below

1
kleopatra On BEST ANSWER

Astonishingly, that doesn't seem to be supported.

The property that changes during the expand/collapse phase is the content's height: so a hack around might be to listen to it and start editing when fully expanded (which is a bit hacky in itself, could change due to layout constraints as well).

The example below simply initializes the fully expanded height after showing, listens to content's height property and starts editing when it reaches the fully expanded height.

The code:

public class TitledPaneEndOfExpansion extends Application {

    private DoubleProperty expandedHeight = new SimpleDoubleProperty();
    private TitledPane titled = new TitledPane();
    private Parent createContent() {
        titled.setText("Titled");
        ListView<String> list = new ListView<>(FXCollections.observableArrayList("some", "content"));
        list.setEditable(true);
        list.setCellFactory(TextFieldListCell.forListView());
        titled.setContent(list);
        list.heightProperty().addListener((src, ov, nv) -> {
            if (nv.doubleValue() == expandedHeight.get()) {
                list.edit(0);
            }
        });
        BorderPane content = new BorderPane(titled);
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setTitle(FXUtils.version());
        stage.show();
        expandedHeight.set(((Region) titled.getContent()).getHeight());
    }

    public static void main(String[] args) {
        launch(args);
    }

}
0
Michael W. On

Basically I like kleopatras idea, but unfortunately I can't figure out if this works for me or not.
At first I had some problems reading the code - only because my java knowledge is very limited. So I transferred it to scala. When I run it there, the call to edit works only sometimes (after startup it does not, when i clicked into a cell to edit it does). So I added a button that also calls edit - and it had the same behavior. So calling edit in general seems to have a problem in scalafx. But I learned something interesting here. I will now wait a few more days to see if anyone can think of anything else. If not then I will accept kleopatras solution.

For my own reference I add my not working scala-code here:

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.beans.property.DoubleProperty
import scalafx.beans.value.ObservableValue
import scalafx.collections.ObservableBuffer
import scalafx.event.ActionEvent
import scalafx.scene.Scene
import scalafx.scene.control.cell.TextFieldListCell
import scalafx.scene.control.{Button, ListView, TitledPane}
import scalafx.scene.layout.BorderPane

object TitledPaneEndOfExpansion extends JFXApp {
  val expandedHeight = new DoubleProperty()
  val data: ObservableBuffer[String] = new ObservableBuffer[String]() ++= List("some", "content", "for", "testing")

  stage = new JFXApp.PrimaryStage {
    title = "JavaFX: edit after rendering test"

    val list: ListView[String] = new ListView[String](data) {
      editable = true
      cellFactory = TextFieldListCell.forListView()
      height.onChange { (source: ObservableValue[Double, Number], oldValue: Number, newValue: Number) =>
        println("old height is: " + oldValue.doubleValue() + "   new height is: " + newValue.doubleValue())
        if (newValue.doubleValue() == expandedHeight.value) {
          edit(1)
        }
      }
    }

    val titled: TitledPane = new TitledPane {
      text = "titled"
      content = list
    }

    scene = new Scene {
      root = new BorderPane {
        center = titled
        bottom = new Button() {
          text = "edit cell 1"
          onAction = { _: ActionEvent => list.edit(1) }
        }
      }
    }
    expandedHeight.value = 400
    list.edit(1)
  }
}