我在JavaFX中使用treeview来实现文件浏览器。我将Tab中的树视图设置为conent。当我使用预定线程刷新树视图元素时,我无法滚动到以前选择的树项。这是我的最低版本。
/**
*
* @author nika
*/
public class TabTreeView extends Application implements Runnable {
private TreeItem<String> root;
private TreeView<String> tv = new TreeView<>();
private static ArrayList<NumberPair> rememberExpanded = new ArrayList<>();
private TreeItem<String> previouslySelectedTreeItem;
@Override
public void run() {
root = new TreeItem<>("Root");
root.setExpanded(true);
for (int i = 0; i < 10; i++) {
TreeItem<String> sublevel = new TreeItem<>("Level : " + i + " TS: " + System.currentTimeMillis());
final int level = i;
if (rememberExpanded.contains(new NumberPair(level, -9999))) {
sublevel.setExpanded(true);
}
sublevel.expandedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
rememberExpanded.add(new NumberPair(level, -9999));
} else {
rememberExpanded.remove(new NumberPair(level, -9999));
}
}
});
for (int j = 0; j < 5; j++) {
TreeItem<String> subsublevel = new TreeItem<>("SubLevel : " + j + " @ " + i + " TS:" + System.currentTimeMillis());
final int level2 = j;
if (rememberExpanded.contains(new NumberPair(level, level2))) {
sublevel.setExpanded(true);
}
subsublevel.expandedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
rememberExpanded.add(new NumberPair(level, level2));
} else {
rememberExpanded.remove(new NumberPair(level, level2));
}
}
});
sublevel.getChildren().add(subsublevel);
}
root.getChildren().add(sublevel);
}
Platform.runLater(new Runnable() {
@Override
public void run() {
tv.setRoot(root);
//scroll to previously selected item
//i know this one is wrong 1. "as it is not working", 2. "because it will only look into children of root not grandchildren".
tv.scrollTo(root.getChildren().indexOf(previouslySelectedTreeItem));
}
});
}
@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabpane = new TabPane();
tv.selectionModelProperty().addListener(new ChangeListener<MultipleSelectionModel<TreeItem<String>>>() {
@Override
public void changed(ObservableValue<? extends MultipleSelectionModel<TreeItem<String>>> observable, MultipleSelectionModel<TreeItem<String>> oldValue, MultipleSelectionModel<TreeItem<String>> newValue) {
previouslySelectedTreeItem = newValue.getSelectedItem();
}
});
Tab t = new Tab("Demo", tv);
tabpane.getTabs().add(t);
BorderPane bp = new BorderPane(tabpane);
primaryStage.setScene(new Scene(bp));
primaryStage.show();
ScheduledExecutorService exc = Executors.newScheduledThreadPool(1);
exc.scheduleAtFixedRate(this, 0, 2, TimeUnit.SECONDS);
}
public static void main(String[] args) throws Exception {
launch(TabTreeView.class, args);
}
private class NumberPair {
int first, second;
public NumberPair(int first, int second) {
this.first = first;
this.second = second;
}
public int getFirst() {
return first;
}
public void setFirst(int first) {
this.first = first;
}
public int getSecond() {
return second;
}
public void setSecond(int second) {
this.second = second;
}
@Override
public int hashCode() {
int hash = 3;
hash = 37 * hash + this.first;
hash = 37 * hash + this.second;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final NumberPair other = (NumberPair) obj;
if (this.first != other.first) {
return false;
}
if (this.second != other.second) {
return false;
}
return true;
}
@Override
public String toString() {
return "NumberPair{" + "first=" + first + ", second=" + second + '}';
}
}
}
无论如何要记住滚动tabcontent或treeview的位置?这样我可以在刷新视图后恢复滚动位置。
在这个实现中,我添加了一个NumberPair
类来记住扩展项目。
答案 0 :(得分:1)
你可以通过styleclass找到TreeView的ScrollBar参考。试试这个。
Platform.runLater(new Runnable() {
@Override
public void run() {
double position[] = new double[]{0.0d};
Optional<ScrollBar> scroll = findScrollBar(tv, Orientation.VERTICAL);
scroll.ifPresent(s -> position[0] = s.getValue());
tv.setRoot(root);
scroll.ifPresent(s -> s.setValue(position[0]));
}
});
private Optional<ScrollBar> findScrollBar(TreeView<String> from, Orientation orientation) {
Set<Node> nodes = from.lookupAll(".scroll-bar");
return nodes.stream()
.filter(node -> node instanceof ScrollBar && ((ScrollBar)node).getOrientation() == orientation)
.map(node -> ((ScrollBar)node))
.findFirst();
}
但请注意,尝试在TreeItem中保留相同的项目可能是一个很好的方法。只要您从唯一的根添加和删除项目,TreeView就会被设置为保留选择扩展和滚动位置。