使用 JCheckBox 节点渲染 JTree

2024-02-13

我正在尝试修改标准 Swing JTree 以混合带有和不带有复选框的节点。这是一个例子:

当我尝试选中/取消选中其中一个复选框(本例中的“User 01”节点)时,树会丢失节点:

我的代码是此示例的改编:.

而不是像这样将 JCheckBox 嵌入到 DefaultMutableTreeNode 中:

new DefaultMutableTreeNode(new CheckBoxNode("Accessibility", true));

我认为创建一个派生自 DefaultMutableTreeNode(我称之为 JTreeNode)的模型节点更有意义。此类自动将 DefaultMutableTreeNode 的 UserObject 设置为 JCheckBox。 TreeCellRenderer 使用类的 ShowCheckBox 属性来确定是使用 JCheckBox 还是 DefaultTreeCellRenderer。 JTreeNode 的使用方式如下:

    JTreeNode user01 = new JTreeNode("User 01");
    user01.setShowCheckBox(true);
    user01.setSelected(true);

我认为问题出在实现 TreeCellEditor 的类上,特别是在 getCellEditorValue() 或 getTreeCellEditorComponent() 方法中。我怀疑这个问题与 getCellEditorValue() 返回 DefaultMutableTreeNode 的衍生物有关,而不是更简单的模型实例。

public Object getCellEditorValue() {

    JCheckBox checkBox = renderer.getCheckBoxRenderer();

    JTreeNode node = new JTreeNode(checkBox.getText());
    node.setShowCheckBox(true);
    node.setSelected(checkBox.isSelected());
    return node;

}

public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {

    Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);

    // editor always selected / focused
    ItemListener itemListener = new ItemListener() {
        public void itemStateChanged(ItemEvent itemEvent) {
            if (stopCellEditing()) {
                fireEditingStopped();
            }
        }
    };

    if (editor instanceof JCheckBox) {
        ((JCheckBox) editor).addItemListener(itemListener);
    }

    return editor;

}

这是 TreeCellRender 的 getTreeCellRendererComponent() 方法:

public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {

    Component component;

    //if object being passed for rendering is a JTreeNode that should show a JCheckBox, attempt to render it so
    if (((JTreeNode) value).getShowCheckBox()) {

        String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);

        //set default JCheckBox rendering
        checkBoxRenderer.setText(stringValue);
        checkBoxRenderer.setSelected(false);    //not checked
        checkBoxRenderer.setEnabled(tree.isEnabled());

        if (selected) {
            //removed colorization
            //checkBoxRenderer.setForeground(selectionForeground);
            //checkBoxRenderer.setBackground(selectionBackground);
        }
        else {
            checkBoxRenderer.setForeground(textForeground);
            checkBoxRenderer.setBackground(textBackground);
        }

        //DefaultMutableTreeNode
        if ((value != null) && (value instanceof JTreeNode)) {

            //userObject should be a JTreeNode instance
            //DefaultMutableTreeNode
            //Object userObject = ((JTreeNode) value).getUserObject();

            //if it is
            //if (userObject instanceof JTreeNode) {
                //cast as a JTreeNode
                //JTreeNode node = (JTreeNode) userObject;
                JTreeNode node = (JTreeNode) value;

                //set JCheckBox settings to match JTreeNode's settings
                checkBoxRenderer.setText(node.getText());
                checkBoxRenderer.setSelected(node.isSelected());

            //}

        }

        component = checkBoxRenderer;

    }

    //if not, render the default
    else {

        component = defaultRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);

    }

    return component;

}

任何想法都将不胜感激。


我能够解决这个问题。

我创建了一个模型类(TreeNodeModel)来保存相关的节点数据:key、value、hasCheckBox、isSelected:

public class TreeNodeModel {

    int key;
    String value;
    boolean isSelected=false;
    boolean hasCheckBox=false;

    public TreeNodeModel() {
    }
    public TreeNodeModel(int key, String value) {
        this.key=key;
        this.value = value;
    }
    public TreeNodeModel(int key, String value, boolean hasCheckBox) {
        this.key=key;
        this.value = value;
        this.hasCheckBox = hasCheckBox;
    }
    public TreeNodeModel(int key, String value, boolean hasCheckBox, boolean isSelected) {
        this.key=key;
        this.value = value;
        this.hasCheckBox=hasCheckBox;
        this.isSelected = isSelected;
    }

    public boolean isSelected() {
        return this.isSelected;
    }
    public void setSelected(boolean newValue) {
        this.isSelected = newValue;
    }

    public boolean hasCheckBox() {
        return this.hasCheckBox;
    }
    public void setCheckBox(boolean newValue) {
        this.hasCheckBox=newValue;
    }

    public int getKey() {
        return this.key;
    }
    public void setKey(int newValue) {
        this.key = newValue;
    }

    public String getValue() {
        return this.value;
    }
    public void setValue(String newValue) {
        this.value = newValue;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[" + this.value + "/" + this.isSelected + "]";
//        return this.text;
    }

}

我创建了 TreeCellEditor 接口的实现:

public class TreeNodeEditor  extends AbstractCellEditor implements TreeCellEditor {

    private JTree tree;
    private TreeNodeModel editedModel = null;

    TreeNodeRenderer renderer = new TreeNodeRenderer();

    public TreeNodeEditor(JTree tree) {
        this.tree=tree;
    }

    @Override
    public boolean isCellEditable(EventObject event) {

        boolean editable=false;

        if (event instanceof MouseEvent) {

            MouseEvent mouseEvent = (MouseEvent) event;
            TreePath path = tree.getPathForLocation(mouseEvent.getX(),mouseEvent.getY());

            if (path != null) {

                Object node = path.getLastPathComponent();

                if ((node != null) && (node instanceof DefaultMutableTreeNode)) {

                    DefaultMutableTreeNode editedNode = (DefaultMutableTreeNode) node;
                    TreeNodeModel model = (TreeNodeModel) editedNode.getUserObject();
                    editable = model.hasCheckBox;

                }   //if (node)
            }   //if (path)
        }   //if (MouseEvent)

        return editable;

    }

    public Object getCellEditorValue() {

        JCheckBox checkbox = renderer.getCheckBoxRenderer();

        TreeNodeModel model = new TreeNodeModel(editedModel.getKey(), checkbox.getText(), true, checkbox.isSelected());
        return model;

    }

    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {

        if (((DefaultMutableTreeNode) value).getUserObject() instanceof TreeNodeModel) {
            editedModel = (TreeNodeModel) ((DefaultMutableTreeNode) value).getUserObject();
        }

        Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);

        // editor always selected / focused
        ItemListener itemListener = new ItemListener() {
            public void itemStateChanged(ItemEvent itemEvent) {
                if (stopCellEditing())
                    fireEditingStopped();
            }
        };

        if (editor instanceof JCheckBox) {
            ((JCheckBox) editor).addItemListener(itemListener);
        }

        return editor;
    }

}

关键是在 getTreeCellEditorComponent() 方法中捕获模型并在 getCellEditorValue() 方法中使用其 Key。

构建树很容易:

DefaultMutableTreeNode server = new DefaultMutableTreeNode(new TreeNodeModel(0,"Server 01", false));

DefaultMutableTreeNode userFolder = new DefaultMutableTreeNode(new TreeNodeModel(1, "User Folders", false));
server.add(userFolder);

DefaultMutableTreeNode user01 =  new DefaultMutableTreeNode(new TreeNodeModel(2, "User 01", true, true));
userFolder.add(user01);

DefaultMutableTreeNode clientA = new DefaultMutableTreeNode(new TreeNodeModel(3, "Client A", true, true));
user01.add(clientA);

DefaultMutableTreeNode clientB = new DefaultMutableTreeNode(new TreeNodeModel(4, "Client B", true, true));
user01.add(clientB);

DefaultMutableTreeNode publicFolder = new DefaultMutableTreeNode(new TreeNodeModel(5, "Public Folders", false));
server.add(publicFolder);

DefaultMutableTreeNode clientC = new DefaultMutableTreeNode(new TreeNodeModel(6, "Client C", true));
publicFolder.add(clientC);
        Tree_Nodes.setCellRenderer(new TreeNodeRenderer());
        Tree_Nodes.setCellEditor(new TreeNodeEditor(Tree_Nodes));
Tree_Nodes.setModel(new DefaultTreeModel(server);

最后,确定检查哪些节点是检查模型的节点集合(通过按钮)的问题:

private Map<Integer, String> checked = new HashMap<Integer, String>();

private void Button_CheckedActionPerformed(java.awt.event.ActionEvent evt) {

    DefaultTableModel tableModel = ((DefaultTableModel) Table_Nodes.getModel());
    tableModel.getDataVector().removeAllElements();
    tableModel.fireTableDataChanged();

    checked.clear();

    DefaultTreeModel treeModel = (DefaultTreeModel) Tree_Nodes.getModel();
    DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();

    getChildNodes(root);

    for (Iterator it=checked.entrySet().iterator(); it.hasNext(); ) {
        Map.Entry entry = (Map.Entry)it.next();
        tableModel.addRow(new Object[] {entry.getKey(), entry.getValue()});
    }

    Button_Checked.requestFocus();


}

private void getChildNodes(DefaultMutableTreeNode parentNode) {

    for (Enumeration e=parentNode.children(); e.hasMoreElements();) {

        DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) e.nextElement();
        TreeNodeModel model = (TreeNodeModel) childNode.getUserObject();

        if (model.hasCheckBox && model.isSelected()) {
            checked.put(model.getKey(), model.getValue());
        }

        //recurse
        if (childNode.getChildCount()>0) getChildNodes(childNode);

    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 JCheckBox 节点渲染 JTree 的相关文章

  • 如何在 JavaFX 中连接可观察列表?

    我所说的串联是指获得一个新列表 该列表侦听所有串联部分的更改 方法的目的是什么FXCollections concat ObservableList
  • Java 的支持向量机?

    我想用Java编写一个 智能监视器 它可以随时发出警报detects即将到来的性能问题 我的 Java 应用程序正在以结构化格式将数据写入日志文件
  • 什么是抽象类? [复制]

    这个问题在这里已经有答案了 当我了解抽象类时 我说 WT H 问题 创建一个无法实例化的类有什么意义呢 为什么有人想要这样的课程 什么情况下需要抽象类 如果你明白我的意思 最常见的是用作基类或接口 某些语言有单独的interface构建 有
  • 如何调试“com.android.okhttp”

    在android kitkat中 URLConnection的实现已经被OkHttp取代 如何调试呢 OkHttp 位于此目录中 external okhttp android main java com squareup okhttp 当
  • Jframe 内有 2 个 Jdialogs 的 setModal 问题

    当我设置第一个选项时 我遇到了问题JDialog模态 第二个非模态 这是我正在尝试实现的功能 单击 测试对话框 按钮 一个JDialog有名字自定义对话框 主要的将会打开 如果单击 是 选项自定义对话框主 其他JDialog named 自
  • Mockito 使用 @Mock 时将 Null 值注入到 Spring bean 中?

    由于我是 Spring Test MVC 的新手 我不明白这个问题 我从以下代码中获取了http markchensblog blogspot in search label Spring http markchensblog blogsp
  • 如何检查某个元素是否存在于一组项目中?

    In an ifJava中的语句如何检查一个对象是否存在于一组项目中 例如 在这种情况下 我需要验证水果是苹果 橙子还是香蕉 if fruitname in APPLE ORANGES GRAPES Do something 这是一件非常微
  • 如何在 Spring 中使 @PropertyResource 优先于任何其他 application.properties ?

    我正在尝试在类路径之外添加外部配置属性资源 它应该覆盖任何现有的属性 但以下方法不起作用 SpringBootApplication PropertySource d app properties public class MyClass
  • 如何在字段值无效的情况下更改 Struts2 验证错误消息?

    我在 Web 表单上使用 Struts2 验证 如果字段假设为整数或日期 则
  • 使用 Elastic Beanstalk 进行 Logback

    我在使用 Elastic Beanstalk 记录应用程序日志时遇到问题 我正在 AWS Elastic Beanstalk 上的 Tomcat 8 5 with Corretto 11 running on 64bit Amazon Li
  • 不可变的最终变量应该始终是静态的吗? [复制]

    这个问题在这里已经有答案了 在java中 如果一个变量是不可变的并且是final的 那么它应该是一个静态类变量吗 我问这个问题是因为每次类的实例使用它时创建一个新对象似乎很浪费 因为无论如何它总是相同的 Example 每次调用方法时都会创
  • 如何区分从 Saxon XPathSelector 返回的属性节点和元素节点

    给定 XML
  • 使用 HtmlUnit 定位弹出窗口

    我正在构建一个登录网站并抓取一些数据的程序 登录表单是一个弹出窗口 所以我需要访问这个www betexplorer com网站 在页面的右上角有一个登录链接 写着 登录 我单击该链接 然后出现登录弹出表单 我能够找到顶部的登录链接 但找不
  • 列表过滤器内的 Java 8 lambda 列表

    示例 JSON id 1 products id 333 status Active id 222 status Inactive id 111 status Active id 2 products id 6 status Active
  • java 中的蓝牙 (J2SE)

    我是蓝牙新手 这就是我想做的事情 我想获取连接到我的电脑上的蓝牙的设备信息并将该信息写入文件中 我应该使用哪个 api 以及如何实现 我遇到了 bluecove 但经过几次搜索 我发现 bluecove 不能在 64 位电脑上运行 我现在应
  • Log4j2 ThreadContext 映射不适用于parallelStream()

    我有以下示例代码 public class Test static System setProperty isThreadContextMapInheritable true private static final Logger LOGG
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • Java RMI - 客户端超时

    我正在使用 Java RMI 构建分布式系统 它必须支持服务器丢失 如果我的客户端使用 RMI 连接到服务器 如果该服务器出现故障 例如电缆问题 我的客户端应该会收到异常 以便它可以连接到其他服务器 但是当服务器出现故障时 我的客户端什么也
  • 抛出 Java 异常时是否会生成堆栈跟踪?

    这是假设我们不调用 printstacktrace 方法 只是抛出和捕获 我们正在考虑这样做是为了解决一些性能瓶颈 不 堆栈跟踪是在构造异常对象时生成的 而不是在抛出异常对象时生成的 Throwable 构造函数调用 fillInStack
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐