In JavaFX 8 is was able to do the following to always center a selected row in a TableView in the middle of the viewport:
TableView<T> tv = getTableView();
// Position selection in the middle of the viewPort.
if (tv.getSelectionModel().getSelectedItem() != null) {
TableViewSkin<?> ts = (TableViewSkin<?>) tv.getSkin();
Optional<VirtualFlow> vfOpt = ts.getChildren().stream()
.filter(child -> child instanceof VirtualFlow)
.map(VirtualFlow.class::cast)
.findFirst();
// TODO sometimes not centering correctly. The scrollTo used in JavaFX 17
// differs from that used in JavaFX 8!
if (vfOpt.isPresent()) {
VirtualFlow vf = vfOpt.get();
int first = vf.getFirstVisibleCell().getIndex();
int last = vf.getLastVisibleCell().getIndex();
int selectedIndex = tv.getSelectionModel().getSelectedIndex();
int scrollPosition = selectedIndex - ((last - first) / 2) > 0 ? selectedIndex - ((last - first) / 2) : 0;
vf.scrollTo(scrollPosition);
}
}
In JavaFX 17, this no longer works. I tracked it down to the implementation of the vf.scrollTo(int) method, that has gone through some changes compared to JavaFX 8. The code above will sometimes work and sometimes it won't (depending on the first and last index).
I noted down the following (FI = first, LA = last, SEL = selectedIndex, POS = calculated scroll position, RES result):
FI = 0, LA = 16, SEL = 13, POS = 5, RES = to top of viewport
FI = 12, LA = 29, SEL = 13, POS = 5, RES = to middle of viewport
FI = 5, LA = 21, SEL = 13, POS = 5, RES = to top of viewport
So, it appears to have something to do with the calculated position falling already inside the viewport, causing the selected row to go to the top.
Can anyone offer any help?