I want to bind two tableviews together such that they scroll in sync. How do I do that? I am unable to find out how to access the scrollbar of a tableview.
The easiest way I've found to solve the problem is to bind the valueProperty of the visible an the hidden scrollbars.
// Controller
@FXML private TableView tableLeft;
@FXML private TableView tableRight;
@FXML private ScrollBar scrollBar;
@SuppressWarnings("rawtypes")
private void bindScrollBars(TableView> tableView1, TableView> tableView2,
ScrollBar scrollBar, Orientation orientation) {
// Get the scrollbar of first table
VirtualFlow vf = (VirtualFlow)tableView1.getChildrenUnmodifiable().get(1);
ScrollBar scrollBar1 = null;
for (final Node subNode: vf.getChildrenUnmodifiable()) {
if (subNode instanceof ScrollBar &&
((ScrollBar)subNode).getOrientation() == orientation) {
scrollBar1 = (ScrollBar)subNode;
}
}
// Get the scrollbar of second table
vf = (VirtualFlow)tableView2.getChildrenUnmodifiable().get(1);
ScrollBar scrollBar2 = null;
for (final Node subNode: vf.getChildrenUnmodifiable()) {
if (subNode instanceof ScrollBar &&
((ScrollBar)subNode).getOrientation() == orientation) {
scrollBar2 = (ScrollBar)subNode;
}
}
// Set min/max of visible scrollbar to min/max of a table scrollbar
scrollBar.setMin(scrollBar1.getMin());
scrollBar.setMax(scrollBar1.getMax());
// bind the hidden scrollbar valueProterty the visible scrollbar
scrollBar.valueProperty().bindBidirectional(scrollBar1.valueProperty());
scrollBar.valueProperty().bindBidirectional(scrollBar2.valueProperty());
}
/*
* This method must be called in Application.start() after the stage is shown,
* because the hidden scrollbars exist only when the tables are rendered
*/
public void setScrollBarBinding() {
bindScrollBars(this.tableLeft, this.tableRight, this.scrollBar, Orientation.VERTICAL);
}
Now you have to call the binding from Application after the stage is shown and the tables are rendered:
// Application
private MyController controller;
@Override
public void start(Stage primaryStage) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(SalesApp.class.getResource("scene.fxml"));
BorderPane root = (BorderPane) fxmlLoader.load();;
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("app.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
controller = (MyController) fxmlLoader.getController();
controller.setScrollBarBinding();
} catch(Exception e) {
e.printStackTrace();
}
}
Now the tables should scroll synchronously via mouse, key, or scrollbar.
Have fun, Olaf