我有一个简单的模型类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/

10-13 04:42