javafx treeTableView 将子行标记为红色

javafx treeTableView mark children rows red

我在标记 treeTableView 行的颜色时遇到问题。标记“第一级”行没问题,代码功能正常。在 updateItem 方法 -> 项目下,我可以访问第一行水果属性。

但我不知道如何更深入地访问 treeTableView 的“第二级”并为行着色?

下面是我的代码。 在此先感谢您的帮助。

import javafx.fxml.Initializable;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableRow;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ResourceBundle;

public class ControllerWindowTest implements Initializable {

    public TreeTableView<Fruit> treeTableView;
    ArrayList<Fruit> fruitsList = new ArrayList<>(Arrays.asList(
            new Fruit("Apple", "round", "green"), new Fruit("Apple", "round", "red"),
            new Fruit("Apple", "round", "yellow"), new Fruit("Plum", "round", "yellow"),
            new Fruit("Plum", "round", "navy blue"), new Fruit("Plum", "oval", "red")));

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        createTreeTable();
        fillTreeTable();
    }

    public void buttonMarkFruits(){
        treeTableView.setRowFactory(ttv -> new TreeTableRow<Fruit>(){
            @Override
            protected void updateItem(Fruit item, boolean empty) {
                super.updateItem(item, empty);
                //Fruit item - is here "first level" of treeTableView(TreeItem: apples, plums).
                // How to go deeper to second level to access children of apples, plums -
                // where I can check color of fruit and mark treeTable row red??
                if (item == null) {
                    setStyle(null);
                } else if (item.getColor().equals("red")){
                    setStyle("-fx-background-color: tomato;");
                } else {
                    setStyle(null);
                }
            }
        });
    }

    public void createTreeTable(){
        TreeTableColumn<Fruit, String> colName = new TreeTableColumn<>("Fruit");
        TreeTableColumn<Fruit, String> colShape = new TreeTableColumn<>("Shape");
        TreeTableColumn<Fruit, String> colColor = new TreeTableColumn<>("Color");

        colName.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
        colShape.setCellValueFactory(new TreeItemPropertyValueFactory<>("shape"));
        colColor.setCellValueFactory(new TreeItemPropertyValueFactory<>("color"));

        treeTableView.getColumns().addAll(colName, colShape, colColor);
    }

    public void fillTreeTable(){
        TreeItem root = new TreeItem(new Fruit("", "", ""));
        TreeItem apples = new TreeItem(new Fruit("Apple", "", ""));
        TreeItem plums = new TreeItem(new Fruit("Plum", "", ""));
        for (Fruit fruit: fruitsList){
            if (fruit.getName().equals("Apple")){
                apples.getChildren().add(new TreeItem<>(new Fruit("", fruit.getShape(), fruit.getColor())));
            }
            if (fruit.getName().equals("Plum")){
                plums.getChildren().add(new TreeItem<>(new Fruit("", fruit.getShape(), fruit.getColor())));
            }
        }
        root.getChildren().addAll(apples,plums);
        root.setExpanded(true);
        treeTableView.setRoot(root);
        treeTableView.setShowRoot(false);
    }
}

问题不在于行不在树的“第一层”;这是 table 行的 updateItem() 方法在按下按钮时没有被调用。

基本思想是让行观察到某种可观察的 属性,以便它们根据需要更新样式。无论是否按下按钮,都使用该行实现(因此在 initialize() 方法中设置行工厂),并在按下按钮时更新 属性。一个最小的实现如下所示:

public class ControllerWindowTest implements Initializable {

    @FXML
    private TreeTableView<Fruit> treeTableView;
    
    private BooleanProperty redFruitsMarked = new SimpleBooleanProperty(false);
    
    ArrayList<Fruit> fruitsList = new ArrayList<>(Arrays.asList(
            new Fruit("Apple", "round", "green"), new Fruit("Apple", "round", "red"),
            new Fruit("Apple", "round", "yellow"), new Fruit("Plum", "round", "yellow"),
            new Fruit("Plum", "round", "navy blue"), new Fruit("Plum", "oval", "red")));

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        createTreeTable();
        fillTreeTable();
        treeTableView.setRowFactory(ttv -> new TreeTableRow<Fruit>(){
            
            {
                redFruitsMarked.addListener((obs, wereMarked, areNowMarked) -> updateStyles());
            }
            
            @Override
            protected void updateItem(Fruit item, boolean empty) {
                super.updateItem(item, empty);
                updateStyles();
            }
            
            private void updateStyles() {
                                
                if (getItem() == null || (! redFruitsMarked.get())) {
                    setStyle(null);
                } else if (getItem().getColor().equals("red")){
                    setStyle("-fx-background-color: tomato;");
                } else {
                    setStyle(null);
                }
            }
        });
    }

    @FXML
    private void buttonMarkWires(){
        redFruitsMarked.set(true);
    }

    public void createTreeTable(){
        TreeTableColumn<Fruit, String> colName = new TreeTableColumn<>("Fruit");
        TreeTableColumn<Fruit, String> colShape = new TreeTableColumn<>("Shape");
        TreeTableColumn<Fruit, String> colColor = new TreeTableColumn<>("Color");

        colName.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
        colShape.setCellValueFactory(new TreeItemPropertyValueFactory<>("shape"));
        colColor.setCellValueFactory(new TreeItemPropertyValueFactory<>("color"));

        treeTableView.getColumns().addAll(colName, colShape, colColor);
    }

    public void fillTreeTable(){
        TreeItem<Fruit> root = new TreeItem<>(new Fruit("", "", ""));
        TreeItem<Fruit> apples = new TreeItem<>(new Fruit("Apple", "", ""));
        TreeItem<Fruit> plums = new TreeItem<>(new Fruit("Plum", "", ""));
        for (Fruit fruit: fruitsList){
            if (fruit.getName().equals("Apple")){
                apples.getChildren().add(new TreeItem<>(new Fruit("", fruit.getShape(), fruit.getColor())));
            }
            if (fruit.getName().equals("Plum")){
                plums.getChildren().add(new TreeItem<>(new Fruit("", fruit.getShape(), fruit.getColor())));
            }
        }
        root.getChildren().addAll(apples,plums);
        root.setExpanded(true);
        treeTableView.setRoot(root);
        treeTableView.setShowRoot(false);
    }
}