You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为已修改值的CheckBoxTreeItem及其子项设置文本样式

解决方案

要实现仅为修改后的CheckBoxTreeItem设置文本颜色,核心是给目标项添加状态标记,再通过自定义TreeCell绑定CSS伪类来精准控制样式,具体步骤如下:

1. 给TreeItem添加状态标记

为每个CheckBoxTreeItem添加可观察的BooleanProperty,标记该项是否已被修改/移动:

private void addModifiedProperty(CheckBoxTreeItem<String> item) {
    BooleanProperty modified = new SimpleBooleanProperty(false);
    item.getProperties().put("modified", modified);
}

初始化所有TreeItem时调用此方法,给它们设置初始为false的状态标记。

2. 自定义TreeCell绑定CSS伪类

使用CSS伪类能更灵活管理样式,避免硬编码颜色。先定义伪类,再在TreeCell中根据标记属性切换伪类状态:

private static final PseudoClass MODIFIED_PSEUDO_CLASS = PseudoClass.getPseudoClass("modified");

treeView.setCellFactory(param -> {
    CheckBoxTreeCell<String> cell = new CheckBoxTreeCell<>();
    cell.itemProperty().addListener((obs, oldItem, newItem) -> {
        if (newItem != null) {
            BooleanProperty modified = (BooleanProperty) newItem.getProperties().get("modified");
            if (modified != null) {
                // 初始化时设置伪类状态
                cell.pseudoClassStateChanged(MODIFIED_PSEUDO_CLASS, modified.get());
                // 监听标记属性变化,动态切换伪类
                modified.addListener((obs2, oldVal, newVal) -> {
                    cell.pseudoClassStateChanged(MODIFIED_PSEUDO_CLASS, newVal);
                });
            } else {
                cell.pseudoClassStateChanged(MODIFIED_PSEUDO_CLASS, false);
            }
        }
    });
    return cell;
});

3. 添加CSS样式

通过CSS给带有伪类的单元格设置绿色文本:

.tree-cell:modified {
    -fx-text-fill: green;
}

可以将CSS写入单独的.css文件,或像示例中直接嵌入代码。

4. 移动项时标记状态

在移动按钮的点击事件中,将目标项的modified属性设为true,触发样式更新:

moveBtn.setOnAction(e -> {
    // 假设从leftTreeView移动选中项到rightTreeView
    TreeView<String> leftTree = ...;
    TreeView<String> rightTree = ...;
    CheckBoxTreeItem<String> selectedNode = (CheckBoxTreeItem<String>) leftTree.getSelectionModel().getSelectedItem();
    
    // 移除原TreeView的项
    ((CheckBoxTreeItem<String>)leftTree.getRoot()).getChildren().remove(selectedNode);
    // 添加到目标TreeView
    ((CheckBoxTreeItem<String>)rightTree.getRoot()).getChildren().add(selectedNode);
    
    // 标记为已修改
    BooleanProperty modified = (BooleanProperty) selectedNode.getProperties().get("modified");
    if (modified != null) {
        modified.set(true);
        // 触发值变化事件确保视图更新
        Event.fireEvent(selectedNode, new TreeModificationEvent<>(TreeItem.valueChangedEvent(), selectedNode, selectedNode.getValue()));
    }
});

完整可运行示例

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.css.PseudoClass;
import javafx.event.Event;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class DualTreeViewDemo extends Application {
    private static final PseudoClass MODIFIED_PSEUDO_CLASS = PseudoClass.getPseudoClass("modified");

    @Override
    public void start(Stage primaryStage) {
        try {
            // 左侧TreeView初始化
            CheckBoxTreeItem<String> leftRoot = new CheckBoxTreeItem<>("源列表");
            leftRoot.setExpanded(true);
            CheckBoxTreeItem<String> item1 = new CheckBoxTreeItem<>("English");
            CheckBoxTreeItem<String> item2 = new CheckBoxTreeItem<>("Spanish");
            CheckBoxTreeItem<String> item3 = new CheckBoxTreeItem<>("German");
            CheckBoxTreeItem<String> item4 = new CheckBoxTreeItem<>("French");
            addModifiedProperty(item1);
            addModifiedProperty(item2);
            addModifiedProperty(item3);
            addModifiedProperty(item4);
            leftRoot.getChildren().addAll(item1, item2, item3, item4);
            TreeView<String> leftTree = new TreeView<>(leftRoot);
            leftTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
            leftTree.setCellFactory(getCheckBoxTreeCellFactory());
            leftTree.setMaxHeight(140);
            leftTree.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));

            // 右侧TreeView初始化
            CheckBoxTreeItem<String> rightRoot = new CheckBoxTreeItem<>("目标列表");
            rightRoot.setExpanded(true);
            TreeView<String> rightTree = new TreeView<>(rightRoot);
            rightTree.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
            rightTree.setCellFactory(getCheckBoxTreeCellFactory());
            rightTree.setMaxHeight(140);
            rightTree.setBorder(new Border(new BorderStroke(Color.BLUE, BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));

            // 移动按钮
            Button moveBtn = new Button("→ 移动选中项 →");
            moveBtn.setOnAction(e -> {
                CheckBoxTreeItem<String> selectedNode = (CheckBoxTreeItem<String>) leftTree.getSelectionModel().getSelectedItem();
                if (selectedNode != null && !selectedNode.equals(leftRoot)) {
                    leftRoot.getChildren().remove(selectedNode);
                    rightRoot.getChildren().add(selectedNode);
                    // 标记为已修改
                    BooleanProperty modified = (BooleanProperty) selectedNode.getProperties().get("modified");
                    if (modified != null) {
                        modified.set(true);
                        Event.fireEvent(selectedNode, new TreeModificationEvent<>(TreeItem.valueChangedEvent(), selectedNode, selectedNode.getValue()));
                    }
                }
            });

            // 布局
            HBox treeBox = new HBox(20, leftTree, moveBtn, rightTree);
            VBox rootBox = new VBox(10, new Label("双TreeView移动示例"), treeBox);
            rootBox.setPadding(new Insets(25));

            Scene scene = new Scene(new Group(rootBox), 650, 250, Color.BEIGE);
            // 添加CSS样式
            scene.getStylesheets().add("data:text/css," +
                    ".tree-cell:modified {-fx-text-fill: green;}");

            primaryStage.setTitle("TreeView移动项样式示例");
            primaryStage.setScene(scene);
            primaryStage.show();

        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    private TreeCellFactory<TreeView<String>, String> getCheckBoxTreeCellFactory() {
        return param -> {
            CheckBoxTreeCell<String> cell = new CheckBoxTreeCell<>();
            cell.itemProperty().addListener((obs, oldItem, newItem) -> {
                if (newItem != null) {
                    BooleanProperty modified = (BooleanProperty) newItem.getProperties().get("modified");
                    if (modified != null) {
                        cell.pseudoClassStateChanged(MODIFIED_PSEUDO_CLASS, modified.get());
                        modified.addListener((obs2, oldVal, newVal) -> {
                            cell.pseudoClassStateChanged(MODIFIED_PSEUDO_CLASS, newVal);
                        });
                    } else {
                        cell.pseudoClassStateChanged(MODIFIED_PSEUDO_CLASS, false);
                    }
                }
            });
            return cell;
        };
    }

    private void addModifiedProperty(CheckBoxTreeItem<String> item) {
        BooleanProperty modified = new SimpleBooleanProperty(false);
        item.getProperties().put("modified", modified);
    }

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

内容的提问来源于stack exchange,提问作者Srikant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:55:18