JavaFX:TreeTableView Selection Listener意外行为

时间:2017-01-19 09:20:07

标签: javafx listener selection

我想在我的TreeTable视图中应用一个监听器来进行选择更改。无论如何它的行为不像预期的那样。

这是我的数据模型:

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);,我希望每次选择一个项目时,其他所有其他项目都会被取消选择。

我的代码输出是:

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

1 个答案:

答案 0 :(得分:1)

不幸的是,这个选择模型的工作原理并非如此(TreeTableViewArrayListSelectionModel)。

尽管ObservableList selectedItems,但ReadOnlyUnbackedObservableList属性并不总是会通知您有关其更改的信息(通过SelectionMode == SINGLE实施但未提供任何通知 - 它是创建和发出它们的选择模型)。

如果quietClearSelection,选择模型在被命令选择另一行时几乎总是执行SelectionMode.SINGLE - 这只会删除所有选择项而不会让观察者了解这一事实。

那么,为什么手动点击行时它能正常工作? 我已经检查了鼠标单击一行后调用的方法 - 在clearAndSelect的情况下,它始终是SINGLE方法。

我确信这是一份没有记录的合同,当选择模型为SINGLE所有&#34;用户&#34;应该在选择另一行之前清除选择(因为选择两行或更多行是非法的)。

在我看来,使用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); } }); 属性 - 下面你可以找到一个有效的例子:

{{1}}