1

我正在尝试在 JavaFX 中设置一个复选框树,其中叶子绑定到它们的父母:

  • 选择父时选择它们
  • 不能单独更改。

我使用与selectedProperty.

它工作得很好,但每次我选择或取消选择父级时都会引发异常。

有没有简单的方法解决这个问题?除了那些讨厌的例外,我讨厌放弃一种可行的方法。

相关代码如下。请原谅任何 Java 约定错误 - 我还是该语言的新手。

控制器:

package application;

import java.util.ArrayList;
import java.util.List;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;

public class BindingTestController {

@FXML
private TreeView<String> MainTree;


static List<CheckBoxTreeItem<String>> treeItems = new ArrayList<CheckBoxTreeItem<String>>();


CheckBoxTreeItem<String> root = new CheckBoxTreeItem<String>("Root");
CheckBoxTreeItem<String> parent1 = new CheckBoxTreeItem<String>("Parent1");
CheckBoxTreeItem<String> parent2 = new CheckBoxTreeItem<String>("Parent2");


private void AddColumns(CheckBoxTreeItem<String> item){

    for (int i = 1 ; i < 5 ; i++){
        CheckBoxTreeItem<String> itemColumn = new CheckBoxTreeItem<String>(item.getValue()+"_Column_"+i);
        treeItems.add(itemColumn);
        item.getChildren().add(itemColumn);

        itemColumn.selectedProperty().bind(item.selectedProperty());

    }
}




@FXML // This method is called by the FXMLLoader when initialization is complete
private void initialize() {

    treeItems.add(root);
    treeItems.add(parent1);
    root.getChildren().add(parent1);
    treeItems.add(parent2);
    root.getChildren().add(parent2);

    AddColumns(parent1);
    AddColumns(parent2);

    MainTree.setRoot(root);
    MainTree.setShowRoot(true);
    root.setExpanded(true);

       MainTree.setCellFactory(p-> new CheckBoxTreeCell()); 

      MainTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
     MainTree.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
            @Override
            public void changed(ObservableValue observable, Object oldValue, Object newValue) {

                CheckBoxTreeItem<String> treeItem = (CheckBoxTreeItem)newValue;

            }
        });


}


}

这是 FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>

<BorderPane xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.BindingTestController">
   <center>
      <VBox prefHeight="1049.0" prefWidth="714.0"BorderPane.alignment="CENTER">
         <children>
            <TreeView fx:id="MainTree" prefHeight="624.0" prefWidth="714.0"/>
         </children>
      </VBox>
   </center>
 </BorderPane>

这是主要的:

package application;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;


public class Main extends Application {
@Override
public void start(Stage primaryStage) {
    try {
        //          BorderPane root = new BorderPane();
        BorderPane root = (BorderPane) FXMLLoader.load(Main.class.getResource("BindingTest.fxml"));
        Scene scene = new Scene(root,400,400);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    launch(args);
    }
}

任何意见,将不胜感激。

4

1 回答 1

2

问题来自这条线

itemColumn.selectedProperty().bind(item.selectedProperty());

要了解为什么无论您选择什么节点都会出现异常,您应该查看以下的IndependentPropertyCheckBoxTreeItem

CheckBoxTreeItem 可以是独立的或依赖的。默认情况下,CheckBoxTreeItem 实例是依赖的,这意味着对 TreeItem 的选择状态的任何更改都会对父 CheckBoxTreeItem 实例和子 CheckBoxTreeItem 实例产生影响。如果 CheckBoxTreeItem 设置为独立,这意味着对该 CheckBoxTreeItem 的任何更改都不会直接影响父 CheckBoxTreeItem 实例和子 CheckBoxTreeItem 实例的状态。

这意味着,当您选择/取消选择树中具有子节点的节点时,默认情况下它将选择/取消选择它的所有子节点(并且还设置其父节点的选中、未选中、不确定状态,但这在你的情况)。这是您需要的功能之一,您可以直接使用它。

现在您可以理解为什么您的绑定有问题了:您将selectedProperty()子节点的 绑定到selectedProperty()父节点的 ,然后:

  • 如果你检查其中一个叶子节点,你会得到一个异常,因为该值是绑定的,并且无法设置绑定值。

  • 如果您检查其中一个父节点,它将尝试选择其所有子节点(因为是依赖的),然后您将再次遇到异常。

解决方案

你有两个要求:

  • select all of the children nodes, when the parent is selected, which is already done

  • 不允许手动选择子节点

对于第二个要求,您可以禁用这些项目的复选框。为此,您可以使用您的setCellFactory方法TreeView

MainTree.setCellFactory((item) -> {
    return new CheckBoxTreeCell<String>(){

        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if(item != null) {
                this.disableProperty().unbind();
                CheckBoxTreeItem<String> value = (CheckBoxTreeItem<String>) treeItemProperty().getValue();
                this.disableProperty().bind(value.leafProperty());
            }
        }
    };
});

此代码段将disableProperty显示CheckBoxTreeCell对象的 绑定到相应的LeafPropertyCheckBoxTreeItem

public final ReadOnlyBooleanProperty leafProperty()

表示 TreeItem 叶属性,如果 TreeItem 没有子级,则为 true。

这会导致一棵树,其中所有没有子节点的节点都被禁用。

在此处输入图像描述

要使其正常工作,您应该从代码中删除此行:

itemColumn.selectedProperty().bind(item.selectedProperty());

你应该替换这一行

MainTree.setCellFactory(p-> new CheckBoxTreeCell()); 

使用上面发布的代码。

于 2016-07-08T16:26:29.797 回答