我遇到了一个我无法弄清楚的问题。我正在使用名为treeModel
的TreeView并使用setCellFactory
设置单元格,如代码所示。现在在updateItem中,我将CheckBox
设置为图形,并将其与名为CheckBoxTreeItemModel
的CheckBoxTreeItem自定义类相关联。现在,每次updateItem
运行时,都会创建一个新的CheckBox
,并为其创建新的ChangeListener
。
现在起初一切看起来都很正常。然后我展开根的直接子节点,并开始检查项目,但是监听器似乎被多次调用。对于展开的每个级别的TreeItem,这是在root的一个后代上调用监听器的次数。如果我点击一个孩子,一些人离开父母,那么这些听众也会被多次调用。它的奇怪行为可能很难解释,但重点是我不认为听众被多次调用。它好像是缓存的。问题代码如下。任何帮助理解为什么会发生这种情况将不胜感激。
treeModel.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
@Override
public TreeCell<String> call(TreeView<String> param) {
return new TreeCell<String>() {
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
final TreeCell<String> currCell = this;
this.setOnMouseClicked(new EventHandler<MouseEvent>() {
/*mouse event stuff completely unrelated to problem*/
});
if (empty) {
setText(null);
setGraphic(null);
}
else {
TreeItem<String> treeItem = getTreeItem();
if (treeItem instanceof CheckBoxTreeItemModel) {
System.out.println("Being called.");
final CheckBoxTreeItemModel chkTreeItem = (CheckBoxTreeItemModel) treeItem;
setText(item.toString());
CheckBox chk = new CheckBox();
chk.setSelected(chkTreeItem.getDeleteTick());
if(chkTreeItem.getListener() == null) {
ChangeListener<Boolean> listener = new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable,
Boolean oldValue, Boolean newValue) {
if(newValue) {
//was checked
System.out.println(chkTreeItem.toString()+" was checked!");
chkTreeItem.setDeleteTick(newValue);
}
else {
System.out.println(chkTreeItem.toString()+" was un-checked!");
chkTreeItem.setDeleteTick(newValue);
}
}//end of changed method
};
chkTreeItem.setListener(listener);
}
chk.selectedProperty().removeListener(chkTreeItem.getListener());
chk.selectedProperty().addListener(chkTreeItem.getListener());
chk.indeterminateProperty().bindBidirectional(chkTreeItem.indeterminateProperty());
chk.selectedProperty().bindBidirectional(chkTreeItem.selectedProperty());
setGraphic(chk);
}
else {
setText(item.toString());
setGraphic(null);
}
}
}//end of updateItem
};
}//end of the call method
});
答案 0 :(得分:0)
建议的方法
我建议您删除大部分代码并使用内置的CheckBoxTreeCell和CheckBoxTreeItem类。我不确定内置单元格是否符合您的要求,但即使它们没有,您也可以检查它们的源代码并与您的源代码进行比较,它(应该)开始让您对自己的位置有所了解出错了。
您的代码中的潜在问题
重现您的问题需要的代码数量超过您当前提供的代码数量。但有些事情要寻找:
删除和添加相同的侦听器毫无意义:
// first line is redundant.
// all listener code is probably unnecessary as you already bindBidirectional.
chk.selectedProperty().removeListener(chkTreeItem.getListener());
chk.selectedProperty().addListener(chkTreeItem.getListener());
updateItem
。不要每次都为该单元创建新节点,而是重用为该单元创建的现有节点。
// replace with a lazily instantiated CheckBox member reference in TreeCell instance.
CheckBox chk = new CheckBox();
你bindBiDirectional
但从未解除绑定值。
// should also unbind this values.
chk.indeterminateProperty().bindBidirectional(chkTreeItem.indeterminateProperty());
chk.selectedProperty().bindBidirectional(chkTreeItem.selectedProperty());
示例代码
来自内置updateItem
代码的示例CheckBoxTreeCell
代码:
public class CheckBoxTreeCell<T> extends DefaultTreeCell<T> {
. . .
private final CheckBox checkBox;
private ObservableValue<Boolean> booleanProperty;
private BooleanProperty indeterminateProperty;
. . .
@Override public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
StringConverter c = getConverter();
TreeItem<T> treeItem = getTreeItem();
// update the node content
setText(c != null ? c.toString(treeItem) : (treeItem == null ? "" : treeItem.toString()));
checkBox.setGraphic(treeItem == null ? null : treeItem.getGraphic());
setGraphic(checkBox);
// uninstall bindings
if (booleanProperty != null) {
checkBox.selectedProperty().unbindBidirectional((BooleanProperty)booleanProperty);
}
if (indeterminateProperty != null) {
checkBox.indeterminateProperty().unbindBidirectional(indeterminateProperty);
}
// install new bindings.
// We special case things when the TreeItem is a CheckBoxTreeItem
if (treeItem instanceof CheckBoxTreeItem) {
CheckBoxTreeItem<T> cbti = (CheckBoxTreeItem<T>) treeItem;
booleanProperty = cbti.selectedProperty();
checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty);
indeterminateProperty = cbti.indeterminateProperty();
checkBox.indeterminateProperty().bindBidirectional(indeterminateProperty);
} else {
Callback<TreeItem<T>, ObservableValue<Boolean>> callback = getSelectedStateCallback();
if (callback == null) {
throw new NullPointerException(
"The CheckBoxTreeCell selectedStateCallbackProperty can not be null");
}
booleanProperty = callback.call(treeItem);
if (booleanProperty != null) {
checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty);
}
}
}
}
. . .
}