嵌套JavaFX的TreeView的有效填充

时间:2019-06-20 14:21:10

标签: java javafx treeview

“我的班级类别”本身可以具有parentCategory或作为根Category,然后将parentCategory设置为null。每个Category可能都有子类别

我的Category类的代码:

public class Category extends AbstractEntity<Integer> {

    @ManyToOne(cascade = { CascadeType.ALL, CascadeType.REMOVE })
    @JoinColumn(name = "parentCategory_id")
    private Category parentCategory;

    @OneToMany(mappedBy = "parentCategory", fetch = FetchType.EAGER)
    private Set<Category> subcategories;
    private String name;

    @OneToMany(cascade = { CascadeType.ALL, CascadeType.REMOVE }, fetch = FetchType.EAGER)
    private List<Item> items;

    public Category(String name) {
    this.subcategories = new HashSet<>();
    this.name = name;
    this.items = new ArrayList<>();
    }
...
}

假设我的数据库中有很多带有子类别的类别。我想用javafx的TreeView来显示类别的层次结构,但是要以通用的方式显示而无需手动填充TreeItem。不幸的是,我可以轻松地仅显示根类别的直接子类别

我测试过的代码:

    public void initialize(URL paramURL, ResourceBundle paramResourceBundle) {

    List<Category> categoriesAll = categoryDao.findAll();

    categories.getSelectionModel().selectedItemProperty()
        .addListener((ObservableValue<? extends Category> observable, Category oldValue, Category newValue) -> {

        });

    categories.getItems().addAll(FXCollections.observableArrayList(categoriesAll));

    TreeItem<String> rootNode = new TreeItem<>("Categories");
    rootNode.setExpanded(true);

    List<Category> superCategories = categoriesAll.stream().filter(category -> !category.hasParentCategory())
        .collect(Collectors.toList());

    Map<Category, TreeItem<String>> nodesMap = new HashMap<>();
    for (Category cat : superCategories) {
        TreeItem<String> leaf = new TreeItem<String>(cat.getName());
        addTreeItems(0, cat, nodesMap);
        rootNode.getChildren().add(leaf);
    }

    rootNode.getChildren().get(0).getChildren().add(nodesMap.entrySet().stream()
        .filter(entry -> entry.getKey().getName().equals("automotive")).findFirst().get().getValue());

    categoriesTree.setRoot(rootNode);

    }

    public void addTreeItems(int index, Category category, Map<Category, TreeItem<String>> nodesMap) {
    // System.out.println(index + " " + category.getName());
    nodesMap.put(category, new TreeItem<String>(category.getName()));
    List<TreeItem<String>> childrenCategories = category.getSubcategories().stream()
        .map(c -> new TreeItem<String>(c.getName())).collect(Collectors.toList());
    nodesMap.get(category).getChildren().addAll(childrenCategories);
    category.getSubcategories().forEach(cat -> addTreeItems(index + 1, cat, nodesMap));
    }

输出为(在treeView组件中):

automotive
|_tires and rims
|_auto parts
|_cars
|_car workshop equipment

但是应该是:

automotive
|_tires and rims
| |_winter tires
| |_summer tires
|_auto parts
|_cars
| |_audi
| | |_a4
| |_nissan
|  |_gtr
|_car workshop equipment

1 个答案:

答案 0 :(得分:0)

因此,我为嵌套数据层次结构的问题提出了解决方案。解决此问题的方法是找到没有父项的根类别。

List<Category> superCategories = categoriesAll.stream().filter(category -> !category.hasParentCategory())
        .collect(Collectors.toList());

然后将每个superCategory视为根本身:

TreeItem<String> rootNode = new TreeItem<>("Categories");
rootNode.setExpanded(true);
superCategories.forEach(superCategory -> Utils.buildRoot(superCategory, rootNode));

buildRoot方法:

public static void buildRoot(Category category, TreeItem<String> root) {
    if (category.hasParentCategory()) {
        TreeItem<String> found = find(root, category.getParentCategory().getName());
        if (found != null) {
            found.getChildren().add(new TreeItem<String>(category.getName()));
        }
    } else {
        root.getChildren().add(new TreeItem<String>(category.getName()));
    }
    category.getSubcategories().forEach(subcategory -> buildRoot(subcategory, root));
}

find方法:

private static TreeItem<String> find(TreeItem<String> root, String value) {
    if (root != null) {
        if (root.getValue().equals(value)) {
            return root;
        }
        ObservableList<TreeItem<String>> children = root.getChildren();
        if (children != null) {
            for (TreeItem<String> child : children) {
                if (child.getValue().equals(value)) {
                    return child;
                }
                return find(child, value);
            }
        }
    }
    return null;
}