JavaFX TableView列CheckBox侦听器

时间:2018-07-19 07:40:29

标签: javafx

我有带有CheckBox的TableColumn。我必须做这个侦听器,我想知道为什么每次单击后侦听器都会加倍。

    selectedColumn.setCellFactory(column -> new CheckBoxTableCell<>());
    selectedColumn.setCellValueFactory(cellData -> {
        Dir dir = cellData.getValue();
        BooleanProperty property = dir.isSelectedProperty();

        property.addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) ->{
            System.out.println(newValue);
        });

        return property;
    });

首先在第i行中单击复选框: 真正 是

第二次取消选择返回: 假 假 假 错误

第三选择返回: 真正 真正 真正 真正 真正 是

为什么? :)

2 个答案:

答案 0 :(得分:2)

之所以发生这种情况,是因为TableView(和ListView等控件)将其内容虚拟化了。从TableView Javadoc:

  

TableView控件旨在可视化无限数量的   数据行,分为几列。

TableView可能容纳大量项目。但是,在屏幕上,您可能随时会看到10-30行(每行对应一个项目)。

没有虚拟化,如果您有100万个项目,它将创建100万个TableRow对象(我们尚未讨论TableCell),每个TableRow都维护所有状态/价值观。这需要大量的内存和处理能力。

另一方面,在虚拟化中,如果您的View仅显示10行,则TableView仅将创建12个TableRow实例。当您滚动浏览列表时,某些项目从您的视线中消失了。这些TableRow实例会立即重新用于您视线中的项目。

这就是setCellFactory()setCellValueFactory()方法为Callback类型的原因。每次重复使用一行时,它将调用此回调对象以更新TableCell。这就是为什么反复添加您的侦听器并导致这种情况的原因。

根据您的需要,可以在项目列表中添加ListChangedListener

ObservableList<Dir> list = FXCollections.observableArrayList(item -> new javafx.beans.Observable[] {item.isSelectedProperty()});
list.addAll(DirList.getDirList());
dirList.setItems(list);

list.addListener(new ListChangeListener<Dir>() {
    @Override public void onChanged(javafx.collections.ListChangeListener.Change<? extends Dir> c) {
        while (c.next()) {
            if (c.wasUpdated()) {
                // Do something
            }
        }
    }
});

答案 1 :(得分:1)

我看到您有一个名为Dir的模型,其中一个名为BooleanProperty的{​​{1}}

您可以简单地将selected设为:

cellValueFactory

如果您在表格单元格中选中/取消选中selectedColumn.setCellValueFactory(cellData -> cellData.getValue().isSelectedProperty());,则会更新模型的属性。

如果使用复选框的选中/取消选中状态,则可以使用模型,然后在其中添加侦听器,您将获得相同的结果。然后,该侦听器将仅添加一次。

您应该创建CheckBox的实例,然后才能进行以下操作。在Dir中:

initialize

或者您想要的任何内容,那么您可以确保只添加一次侦听器。 如@Jai所述,单元数据使用了很多次,每次调用dir1.selectedProperty().addListener((observable, oldValue, newValue) -> { dir2.selectedProperty().set(oldValue); }); 时,都会将侦听器添加到属性中,因此,如果要避免多次添加侦听器,请不要在该方法内使用它时间到属性。