I want to add a new row to a GridPane and make it visible within the containing ScrollPane.
Here's my test mule for Java 17, JFX 19.
package pkg.scrolltest;
// imports ellided
public class App extends Application {
GridPane gridPane;
ScrollPane sp;
@Override
public void start(Stage stage) {
var scene = new Scene(getPane(), 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
public Parent getPane() {
gridPane = new GridPane();
gridPane.add(new Label("First label"), 0, 0);
Button addButton = new Button("Add");
addButton.setOnAction((event) -> {
int rows = gridPane.getRowCount();
gridPane.add(new Label("This is a label " + rows), 0, rows);
sp.setVvalue(1);
});
sp = new ScrollPane(gridPane);
VBox vb = new VBox(addButton, sp);
return vb;
}
}
The sp.setVvalue(1)
should scroll to the end of the wrapped pane.
The problem is, at this point of the lifecycle, while the new label has been added to the GridPane, none of the layout has happened yet, so the GridPane has not got larger, and the ScrollPane has not had an opportunity to react to that growth.
The only way I've come up as a workaround is using a timer to fire the Vvalue change "later", after all of the layout has occurred.
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
Platform.runLater(() -> {
sp.setVvalue(1);
});
}
}, 50);
While this works, it's a bit hand wavy, and I'd like to think I could do this more deterministically.
This does not work:
gridPane.requestLayout();
sp.setVvalue(1);
As I understand it, requestLayout
is just that -- a request, it does not happen in line. Rather it queues it up to happen later.
Is there a better way to do this?
EDIT: Thanks jewelsea, indeed forcing the layout did work. I'm curious why it did not for James_D
gridPane.add(label, 0, rows);
sp.applyCss();
sp.layout();
sp.setVvalue(1);
This worked a charm for me.