【问题标题】:TreeView of objects having child nodes that are fields of the object具有作为对象字段的子节点的对象的 TreeView
【发布时间】:2018-02-26 14:49:08
【问题描述】:

我有一个包含不同数据类型字段的对象:

public class MyObject{
     private String field1;
     private CustomObject field2;
     private int field3;
     ...
}

我想创建一个 MyObject 的树形视图,它有多个 MyObject 节点,每个节点都有字段(field1field2field3..etc)作为子级。

我知道我可以创建一个字符串的 TreeView 并使用 addNode(MyObject obj) 方法自己填充它,我将在其中添加我需要的单个 TreeItems。但是,我使用 TableView 执行此操作,我可以在其中将列与字段属性绑定。如:

TableView<MyObject> table;
TableColumn<MyObject, String> myColumn;
myColumn.setCellValueFactory(new PropertyValueFactory<>("field1"));

有没有办法为TreeView&lt;MyObject&gt; 做类似的事情?我不反对创建一个扩展TreeItem&lt;?&gt;的子类

我正在寻找的最终结果是这样的:

--> First My Object
    ->field1: "Value at Field 1"
    ->field2: "Value at Field 2"
    ->field3: 3
--> Second My Object
    ->field1: "Value at Field 1"
    ->field2: "Value at Field 2"
    ->field3: 3

【问题讨论】:

标签: java model-view-controller javafx data-binding treeview


【解决方案1】:

几乎任何时候您在树的不同节点中使用具有不同类型的TreeView 时,您都需要在某处进行一些强制转换和/或类型检查。

这里一种可能的方法是子类化TreeItem 为您要显示的属性提供一个字段,然后使用显示该属性的字符串值的TreeCell

这是一个非常基本的例子:

import java.util.Arrays;
import java.util.List;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.stage.Stage;

public class TreeViewWithProperties extends Application {

    @Override
    public void start(Stage primaryStage) {
        List<SomeEntity> entities = Arrays.asList(
                new SomeEntity("First object", "String value 1", 42),
                new SomeEntity("Second object", "String value 2", 3)
        );

        TreeView<SomeEntity> tree = new TreeView<>();
        tree.setShowRoot(false);

        TreeItem<SomeEntity> treeRoot = new TreeItem<>();
        tree.setRoot(treeRoot);


        for (SomeEntity entity : entities) {
            TreeItem<SomeEntity> item = PropertyTreeItem.baseItem(entity);
            treeRoot.getChildren().add(item);

            item.getChildren().add(new PropertyTreeItem<String>(entity, entity.getStringField()));
            item.getChildren().add(new PropertyTreeItem<Integer>(entity, entity.getValue()));
        }

        tree.setCellFactory(tv -> new TreeCell<SomeEntity>() {
            @Override
            protected void updateItem(SomeEntity entity, boolean empty) {
                super.updateItem(entity, empty);
                PropertyTreeItem<?> item = (PropertyTreeItem<?>) getTreeItem();
                if (empty) {
                    setText(null);
                } else {
                    setText(item.getPropertyValue().toString());
                }
            }
        });

        Scene scene = new Scene(tree);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class PropertyTreeItem<T> extends TreeItem<SomeEntity> {

        private final T propertyValue ;

        public PropertyTreeItem(SomeEntity entity, T value) {
            super(entity);
            this.propertyValue = value ;
        }

        public static PropertyTreeItem<SomeEntity> baseItem(SomeEntity entity) {
            return new PropertyTreeItem<>(entity, entity);
        }

        public T getPropertyValue() {
            return propertyValue ;
        }
    }

    public class SomeEntity {

        private String name ;
        private String stringField ;
        private int value ;


        public SomeEntity(String name, String stringField, int value) {
            this.name = name;
            this.stringField = stringField;
            this.value = value;
        }

        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getStringField() {
            return stringField;
        }
        public void setStringField(String stringField) {
            this.stringField = stringField;
        }
        public int getValue() {
            return value;
        }
        public void setValue(int value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return name ;
        }
    }

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

当然,这方面的一些变化是可能的。如果您想在实体类中使用 JavaFX 属性,并且能够在树的外部更改这些值,则可以将文本绑定到单元格中的属性,而不是简单地设置它。

【讨论】:

  • 虽然我可以看到这对某人有所帮助,但我认为我不需要那样做,因为无论如何所有字段都将附加到一个字符串中,转换就会完成。我只是希望有一种方法可以自动创建子节点。
  • @KevinFurlong 那么也许你可以问这个,而不是你实际问的问题。
【解决方案2】:

使用我在您的问题下发布的链接中的一些想法。这个例子使用一个帮助类来创建TreeItems

主要

import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class JavaFXApplication128 extends Application
{

    @Override
    public void start(Stage primaryStage)
    {
        MyObject myObject1 = new MyObject("myObject1", "field 1 a", new CustomObject("customObject 1", 3), 5);
        MyObject myObject2 = new MyObject("myObject2", "field 1 b", new CustomObject("customObject 2", 36), 10);
        MyObject myObject3 = new MyObject("myObject3", "field 1 c", new CustomObject("customObject 3", 23), 8);

        List<MyObject> list = new ArrayList();
        list.add(myObject1);
        list.add(myObject2);
        list.add(myObject3);

        List<TreeItem<String>> treeItemsContainer = new ArrayList();
        for (MyObject object : list) {
            ObjectToTreeView objectToTreeView = new ObjectToTreeView(object);
            treeItemsContainer.add(objectToTreeView.getRootItem());
        }

        TreeItem<String> rootItem = new TreeItem();
        rootItem.setExpanded(true);
        rootItem.getChildren().addAll(treeItemsContainer);

        TreeView treeView = new TreeView(rootItem);

        Scene scene = new Scene(treeView, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}

ObjectToTreeView 类

import javafx.scene.control.TreeItem;

/**
 *
 * @author blj0011
 */
public class ObjectToTreeView
{

    private final TreeItem<String> rootItem = new TreeItem();

    public ObjectToTreeView(MyObject myObject)
    {
        rootItem.setValue(myObject.getTitle());

        rootItem.getChildren().add(new TreeItem(myObject.getField1()));
        CustomObject customObject = myObject.getField2();
        rootItem.getChildren().add(new TreeItem(customObject.getName()));
        rootItem.getChildren().add(new TreeItem(customObject.getNumber()));
        rootItem.getChildren().add(new TreeItem(myObject.getField3()));
    }

    /**
     * @return the rootItem
     */
    public TreeItem<String> getRootItem()
    {
        return rootItem;
    }

}

MyObject 类

/**
 *
 * @author blj0011
 */
public class MyObject
{

    private String title;
    private String field1;
    private CustomObject field2;
    private int field3;

    public MyObject(String title, String field1, CustomObject field2, int field3)
    {
        this.title = title;
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
    }

    /**
     * @return the title
     */
    public String getTitle()
    {
        return title;
    }

    /**
     * @param title the title to set
     */
    public void setTitle(String title)
    {
        this.title = title;
    }

    /**
     * @return the field1
     */
    public String getField1()
    {
        return field1;
    }

    /**
     * @param field1 the field1 to set
     */
    public void setField1(String field1)
    {
        this.field1 = field1;
    }

    /**
     * @return the field3
     */
    public int getField3()
    {
        return field3;
    }

    /**
     * @param field3 the field3 to set
     */
    public void setField3(int field3)
    {
        this.field3 = field3;
    }

    /**
     * @return the field2
     */
    public CustomObject getField2()
    {
        return field2;
    }

    /**
     * @param field2 the field2 to set
     */
    public void setField2(CustomObject field2)
    {
        this.field2 = field2;
    }
}

自定义对象类

/**
 *
 * @author blj0011
 */
public class CustomObject
{

    private String name;
    private int number;

    public CustomObject(String name, int number)
    {
        this.name = name;
        this.number = number;
    }

    /**
     * @return the name
     */
    public String getName()
    {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name)
    {
        this.name = name;
    }

    /**
     * @return the number
     */
    public int getNumber()
    {
        return number;
    }

    /**
     * @param number the number to set
     */
    public void setNumber(int number)
    {
        this.number = number;
    }

}

【讨论】:

  • 谢谢,这就是我最终所做的,但我没有使用辅助类,而是在我的控制器中添加了一个函数。
【解决方案3】:

我最终只是通过执行以下操作创建了一个辅助函数:

public TreeItem<String> createNode(MyObject obj) {
        TreeItem<String> node = null;
        if(obj != null) {
            node = new TreeItem<String>("MyObject:" + obj.getId());
            node.getChildren().add(new TreeItem<String>("Field1: "+ obj.getField1()));
            node.getChildren().add(new TreeItem<String>("Field2: "+ obj.getField2()));
            node.getChildren().add(new TreeItem<String>("Field3: "+ obj.getField3()));
        }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多