我有带有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行中单击复选框: 真正 是
第二次取消选择返回: 假 假 假 错误
第三选择返回: 真正 真正 真正 真正 真正 是
为什么? :)
答案 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);
});
时,都会将侦听器添加到属性中,因此,如果要避免多次添加侦听器,请不要在该方法内使用它时间到属性。