Reputation: 130
I would like to keep selected row in the middle of the TableView control regardless of how selection is changing. I have to buttons (PREV, NEXT) above TableView that I use to move change selected rows. The problem is that TableView scrollbar does not follow this selection so I need to call
TableView.scrollTo(int)
to keep selected row visible. However after calling scrollTo(int) selected row ends up on the top of the viewport. And I would like to have it in the middle of the viewport.
This was possible in Swing as shown here: http://www.java2s.com/Code/Java/Swing-JFC/ScrollingaCelltotheCenterofaJTableComponent.htm
Unfortunately, I am unable to solve this issue with JavaFX 8.
Upvotes: 3
Views: 1492
Reputation: 296
An example of calling the show()
method as suggested earlier by @Jakub in Java:
TableViewSkin<?> ts = (TableViewSkin<?>) tableView.getSkin();
VirtualFlow<?> vf = (VirtualFlow<?>) ts.getChildren().get(1);
vf.show(tableView.getSelectionModel().getSelectedIndex())
I also want to draw your attention to the fact that after this method it is not recommended to immediately call the refresh()
method of the tableView
.
Upvotes: 0
Reputation: 165
Just found slightly better solution to almost the same problem, unfortunately still private API, but works with variable row heights and scrolls only when necessary. I believe it's the same code that's called when UP/DOWN arrows are pressed. Instead of manually calculating the scroll position, just call VirtualFlow's .show(rowIndex).
Following code works under JVM1.8, it's Kotlin, but differs only in syntax from Java:
val skin: Skin<*> = tableView.skin
if (skin is SkinBase<*>) {
skin.children
.first { it is VirtualFlow<*> }
.let { it as VirtualFlow<*> }
.show(rowIndex)
}
Keep in mind that VirtualFlow comes to public API in Java 9, so that will require a bit of rework (or maybe just changes in imports).
Upvotes: 1
Reputation: 130
Well this seems to work. It uses non-public API so I am still interested if someone has better solution.
table.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> Platform.runLater(() -> {
TableViewSkin<?> ts = (TableViewSkin<?>) table.getSkin();
VirtualFlow<?> vf = (VirtualFlow<?>)ts.getChildren().get(1);
int first = vf.getFirstVisibleCellWithinViewPort().getIndex();
int last = vf.getLastVisibleCellWithinViewPort().getIndex();
if((newValue.intValue() - ((last - first) / 2)) >= 0) {
vf.scrollTo(newValue.intValue() - ((last - first) / 2));
}
}));
The limitation is that all rows must have same height.
Upvotes: 5