我有一个简单的模型类Person,并用它来填充TreeTableView。我想要一个带有复选框的列,并且想要用我在第一个表中检查的数据填充另一个TreeTableView。似乎是合理的,但是我的问题是通过SetCellValueFactory添加到BooleanProperty的ChangeListener被触发多次,随机触发4至8次(或者似乎是随机的,我没有真正测试过)。
主班:
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.CheckBoxTreeTableCell;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.stage.Stage;
public class ChangeListenerBug extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
// create the treeTableView and colums
TreeTableView<Person> ttv = new TreeTableView<Person>();
TreeTableColumn<Person, String> colName = new TreeTableColumn<>("Name");
TreeTableColumn<Person, Boolean> colSelected = new TreeTableColumn<>("Selected");
ttv.getColumns().add(colName);
ttv.getColumns().add(colSelected);
ttv.setShowRoot(false);
ttv.setEditable(true);
colSelected.setEditable(true);
// set the columns
colName.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
colSelected.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(colSelected));
colSelected.setCellValueFactory(cellData -> {
// binding the cell property with the model
BooleanProperty selected = cellData.getValue().getValue().selectedProperty();
// listening for a change in the property
selected.addListener((obs, oldVal, newVal) -> {
System.out.println(newVal);// WHY IS THIS GETTING CALLED MULTIPLE TIMES
});
return selected;
});
// creating treeItems to populate the treetableview
TreeItem<Person> rootTreeItem = new TreeItem<Person>();
rootTreeItem.getChildren().add(new TreeItem<Person>(new Person("Name 1")));
rootTreeItem.getChildren().add(new TreeItem<Person>(new Person("Name 2")));
ttv.setRoot(rootTreeItem);
// build and show the window
Group root = new Group();
root.getChildren().add(ttv);
stage.setScene(new Scene(root, 300, 300));
stage.show();
}
}
人员类别:
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private StringProperty name;
private BooleanProperty selected;
public Person(String name) {
this.name = new SimpleStringProperty(name);
selected = new SimpleBooleanProperty(false);
}
public StringProperty nameProperty() {return name;}
public BooleanProperty selectedProperty() {return selected;}
public void setName(String name){this.name.set(name);}
public void setSelected(boolean selected){this.selected.set(selected);}
}
当我选中一个复选框时输出(相同但取消选中时为false):
true
true
true
true
true
最佳答案
cellData.getValue().getValue().selectedProperty()
不会创建新的BooleanProperty。对于任何给定的Person对象,它一次又一次返回相同的BooleanProperty,并且您一次又一次地向该相同的BooleanProperty添加另一个侦听器。
不要在cellValueFactory中添加侦听器。将侦听器一次添加到每个Person对象。
由于树仅深一层(除了根),因此可以遍历它们:
rootTreeItem.getChildren().forEach(item -> {
BooleanProperty selected = item.getValue().selectedProperty();
selected.addListener((obs, oldVal, newVal) -> {
System.out.println(newVal);
});
});
如果树有多个级别,则需要一个递归方法:
listenForSelection(rootTreeItem,
selected -> System.out.println(selected));
// ...
private void listenForSelection(TreeItem<Person> treeItem,
Consumer<Boolean> listener) {
BooleanProperty selected = treeItem.getValue().selectedProperty();
selected.addListener(
(obs, oldVal, newVal) -> listener.accept(newVal));
treeItem.getChildren().forEach(item -> listenForSelection(item, listener));
}
关于java - TreeTableView CheckBoxTreeTableCell中的ChangeListener每次单击都会触发多次,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52486256/