JavaFX:TreeTableView 选择侦听器意外行为
JavaFX: TreeTableView Selection Listener unexpected behaviour
我想对我的 TreeTable 视图中的 selection 变化应用监听器。无论如何,它的行为并不像预期的那样。
这是我的数据模型:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class File {
private StringProperty name = new SimpleStringProperty(this, "name");
public File (String name) {nameProperty().set(name); }
public StringProperty nameProperty() {return this.name; }
@Override public String toString() {return name.get().toString() ;}
}
这是我的主要应用程序:
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class treeTableViewTest extends Application {
@Override
public void start(final Stage stage) {
// DemoData =========================================================
File rootFile = new File("/");
TreeItem<File> child2 = new TreeItem<File>(new File("Child 2"));
TreeItem<File> root = new TreeItem<File>(rootFile);
root.getChildren().add(new TreeItem<File>(new File("Child 1")));
root.getChildren().add(child2);
root.getChildren().add(new TreeItem<File>(new File("Child 3")));
root.getChildren().add(new TreeItem<File>(new File("Child 4")));
root.getChildren().add(new TreeItem<File>(new File("Child 5")));
root.setExpanded(true);
child2.getChildren().add(new TreeItem<File>(new File("SubChild 1")));
child2.getChildren().add(new TreeItem<File>(new File("SubChild 2")));
// Layout =========================================================
final StackPane stackPane = new StackPane();
TreeTableView<File> treeTable = new TreeTableView<>();
treeTable.setEditable(true);
treeTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
treeTable.getSelectionModel().setCellSelectionEnabled(false);
treeTable.setRoot(root);
TreeTableColumn<File,String> fileNameCol = new TreeTableColumn<>("Filename");
treeTable.getColumns().setAll(fileNameCol);
fileNameCol.setCellValueFactory(new TreeItemPropertyValueFactory("name"));
stackPane.getChildren().add(treeTable);
stage.setScene(new Scene(stackPane,250,250));
stage.show();
// Selection Listener ================================================
treeTable.getSelectionModel().getSelectedItems().addListener(new ListChangeListener<TreeItem<File>>() {
@Override
public void onChanged(ListChangeListener.Change<? extends TreeItem<File>> c) {
while (c.next()) {
if (c.wasPermutated()) {
for (int i = c.getFrom(); i < c.getTo(); ++i) {
//permutate
}
} else if (c.wasUpdated()) {
System.out.println("updated: " + c.toString());
} else {
for (TreeItem<File> remitem : c.getRemoved()) {
System.out.println("removed: " + remitem.toString());
}
for (TreeItem<File> additem : c.getAddedSubList()) {
System.out.println("added: " + additem.toString());
}
}
for(TreeItem<File> file : c.getList() ){
System.out.println(" -> " + file.toString());
}
}
}});
// Random Interactions =========================================================
treeTable.getSelectionModel().select(3);
treeTable.getSelectionModel().select(5);
treeTable.getSelectionModel().clearAndSelect(1);
}
public static void main(final String[] args){
launch(args);
}
}
因为我已经定义了 treeTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
我希望每次我 select 一个项目时,所有其他项目都会自动删除 selected。
我的代码的输出是:
added: TreeItem [ value: Child 3 ]
-> TreeItem [ value: Child 3 ]
added: TreeItem [ value: Child 5 ]
-> TreeItem [ value: Child 5 ]
removed: TreeItem [ value: Child 5 ]
added: TreeItem [ value: Child 1 ]
-> TreeItem [ value: Child 1 ]
我会期待这个输出:
added: TreeItem [ value: Child 3 ]
-> TreeItem [ value: Child 3 ]
removed: TreeItem [ value: Child 3 ] // <- missing in original output
added: TreeItem [ value: Child 5 ]
-> TreeItem [ value: Child 5 ]
removed: TreeItem [ value: Child 5 ]
added: TreeItem [ value: Child 1 ]
-> TreeItem [ value: Child 1 ]
为什么移除后的Child 3
不能直接在监听器中看到?显然它已被删除,因为它不再在 c.getList()
中。
编辑
问题现在作为错误报告在这里提交:
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8175260
不幸的是,selection 模型不是这样工作的(它是 TreeTableViewArrayListSelectionModel
)。
尽管是 ObservableList
,selectedItems
属性 并不总是通知您它的更改(它是通过 ReadOnlyUnbackedObservableList
实现的,它不提供任何通知 -它是 selection 模型创建和发射它们)。
If SelectionMode == SINGLE
,selection 模型,当被命令到 select 另一行时,几乎总是执行 quietClearSelection
- 这只是删除所有 select离子项目没有通知观察员关于这一事实。
那么,为什么手动点击行时可以正常工作?
我检查了鼠标单击一行后调用的方法 - 在 SelectionMode.SINGLE
的情况下,它始终是 clearAndSelect
方法。
我确信这是一个没有记录的合同,当 selection 模型是 SINGLE
时,所有 "users" 应该在 [=35= 之前清除 selection ]ing 另一行(因为 selecting 两行或更多行是非法的)。
在我看来,使用 SINGLE
selection 模型,您应该观察 selectedItem
属性 - 您可以在下面找到一个工作示例:
treeTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<File>>() {
@Override
public void changed(ObservableValue<? extends TreeItem<File>> observable, TreeItem<File> oldValue, TreeItem<File> newValue) {
System.out.println(oldValue + "->" + newValue);
}
});
我想对我的 TreeTable 视图中的 selection 变化应用监听器。无论如何,它的行为并不像预期的那样。
这是我的数据模型:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class File {
private StringProperty name = new SimpleStringProperty(this, "name");
public File (String name) {nameProperty().set(name); }
public StringProperty nameProperty() {return this.name; }
@Override public String toString() {return name.get().toString() ;}
}
这是我的主要应用程序:
import javafx.application.Application;
import javafx.collections.ListChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class treeTableViewTest extends Application {
@Override
public void start(final Stage stage) {
// DemoData =========================================================
File rootFile = new File("/");
TreeItem<File> child2 = new TreeItem<File>(new File("Child 2"));
TreeItem<File> root = new TreeItem<File>(rootFile);
root.getChildren().add(new TreeItem<File>(new File("Child 1")));
root.getChildren().add(child2);
root.getChildren().add(new TreeItem<File>(new File("Child 3")));
root.getChildren().add(new TreeItem<File>(new File("Child 4")));
root.getChildren().add(new TreeItem<File>(new File("Child 5")));
root.setExpanded(true);
child2.getChildren().add(new TreeItem<File>(new File("SubChild 1")));
child2.getChildren().add(new TreeItem<File>(new File("SubChild 2")));
// Layout =========================================================
final StackPane stackPane = new StackPane();
TreeTableView<File> treeTable = new TreeTableView<>();
treeTable.setEditable(true);
treeTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
treeTable.getSelectionModel().setCellSelectionEnabled(false);
treeTable.setRoot(root);
TreeTableColumn<File,String> fileNameCol = new TreeTableColumn<>("Filename");
treeTable.getColumns().setAll(fileNameCol);
fileNameCol.setCellValueFactory(new TreeItemPropertyValueFactory("name"));
stackPane.getChildren().add(treeTable);
stage.setScene(new Scene(stackPane,250,250));
stage.show();
// Selection Listener ================================================
treeTable.getSelectionModel().getSelectedItems().addListener(new ListChangeListener<TreeItem<File>>() {
@Override
public void onChanged(ListChangeListener.Change<? extends TreeItem<File>> c) {
while (c.next()) {
if (c.wasPermutated()) {
for (int i = c.getFrom(); i < c.getTo(); ++i) {
//permutate
}
} else if (c.wasUpdated()) {
System.out.println("updated: " + c.toString());
} else {
for (TreeItem<File> remitem : c.getRemoved()) {
System.out.println("removed: " + remitem.toString());
}
for (TreeItem<File> additem : c.getAddedSubList()) {
System.out.println("added: " + additem.toString());
}
}
for(TreeItem<File> file : c.getList() ){
System.out.println(" -> " + file.toString());
}
}
}});
// Random Interactions =========================================================
treeTable.getSelectionModel().select(3);
treeTable.getSelectionModel().select(5);
treeTable.getSelectionModel().clearAndSelect(1);
}
public static void main(final String[] args){
launch(args);
}
}
因为我已经定义了 treeTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
我希望每次我 select 一个项目时,所有其他项目都会自动删除 selected。
我的代码的输出是:
added: TreeItem [ value: Child 3 ]
-> TreeItem [ value: Child 3 ]
added: TreeItem [ value: Child 5 ]
-> TreeItem [ value: Child 5 ]
removed: TreeItem [ value: Child 5 ]
added: TreeItem [ value: Child 1 ]
-> TreeItem [ value: Child 1 ]
我会期待这个输出:
added: TreeItem [ value: Child 3 ]
-> TreeItem [ value: Child 3 ]
removed: TreeItem [ value: Child 3 ] // <- missing in original output
added: TreeItem [ value: Child 5 ]
-> TreeItem [ value: Child 5 ]
removed: TreeItem [ value: Child 5 ]
added: TreeItem [ value: Child 1 ]
-> TreeItem [ value: Child 1 ]
为什么移除后的Child 3
不能直接在监听器中看到?显然它已被删除,因为它不再在 c.getList()
中。
编辑
问题现在作为错误报告在这里提交: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8175260
不幸的是,selection 模型不是这样工作的(它是 TreeTableViewArrayListSelectionModel
)。
尽管是 ObservableList
,selectedItems
属性 并不总是通知您它的更改(它是通过 ReadOnlyUnbackedObservableList
实现的,它不提供任何通知 -它是 selection 模型创建和发射它们)。
If SelectionMode == SINGLE
,selection 模型,当被命令到 select 另一行时,几乎总是执行 quietClearSelection
- 这只是删除所有 select离子项目没有通知观察员关于这一事实。
那么,为什么手动点击行时可以正常工作?
我检查了鼠标单击一行后调用的方法 - 在 SelectionMode.SINGLE
的情况下,它始终是 clearAndSelect
方法。
我确信这是一个没有记录的合同,当 selection 模型是 SINGLE
时,所有 "users" 应该在 [=35= 之前清除 selection ]ing 另一行(因为 selecting 两行或更多行是非法的)。
在我看来,使用 SINGLE
selection 模型,您应该观察 selectedItem
属性 - 您可以在下面找到一个工作示例:
treeTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<File>>() {
@Override
public void changed(ObservableValue<? extends TreeItem<File>> observable, TreeItem<File> oldValue, TreeItem<File> newValue) {
System.out.println(oldValue + "->" + newValue);
}
});