ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 在JTree上过滤

2019-09-23 22:02:42  阅读:257  来源: 互联网

标签:jtree swingx java swing


问题

在JTree上应用过滤以避免某些节点/叶子出现在JTree的呈现版本中.理想情况下,我正在寻找一个允许动态过滤器的解决方案,但如果我能让静态过滤器工作,我会很高兴.

为了使它更容易一些,让我们假设JTree只支持渲染,而不支持编辑.应该可以移动,添加,删除节点.

一个示例是JTree上方的搜索字段,并且在键入JTree时将仅显示具有匹配的子树.

一些限制:它将用于可以访问JDK和SwingX的项目中.我想避免包含其他第三方库.

我已经想到了一些可能的解决方案,但这些都不是理想的

途径

基于模型的过滤

>装饰TreeModel以过滤掉一些值.快速而简单的版本很容易编写.过滤掉节点,并且在过滤器或委托TreeModel的每次更改时,装饰器都可以触发整个树发生变化的事件(treeStructureChanged以根节点作为节点).将此与恢复JTree的选择状态和扩展状态的侦听器相结合,您将得到一个或多或少有效的版本,但是源自TreeModel的事件会搞乱.这或多或少是this question中使用的方法
>装饰TreeModel但尝试触发正确的事件.我(还)没有设法提出这个的工作版本.它似乎需要委托TreeModel的副本,以便能够在从委托模型中删除节点时使用正确的子索引触发事件.我认为有更多的时间我可以让它工作,但它只是感觉不对(过滤感觉像视图应该做的事情,而不是模型)
>装饰用于创建初始TreeModel的任何数据结构.但是,这完全是不可重用的,并且可能与为TreeModel编写装饰器一样困难

基于视图的过滤

这似乎是要走的路.过滤不应影响模型,只影响视图.

>我看了RowFilter班.虽然javadoc似乎建议你可以将它与JTree结合使用:

when associated with a JTree, an entry corresponds to a node.

我在RowFilter(或RowSorter)和JTree类之间找不到任何链接. RowFilter和Swing教程的标准实现似乎表明RowFilter只能直接与JTable一起使用(见JTable#setRowSorter). JTree上没有类似的方法
>我也看了JXTree javadoc.它有一个ComponentAdapter可用,ComponentAdapter的javadoc表示RowFilter可以与目标组件进行交互,但是我没看到如何在RowFilter和JTree之间建立链接
>我还没有看到JTable如何使用RowFilters处理过滤,也许可以在修改后的JTree版本上完成相同的操作.

简而言之:我不知道解决这个问题的最佳方法是什么

注意:这个问题可能是this question的重复,但是这个问题仍然没有答案,问题相当简短,答案似乎不完整,所以我想发布一个新问题.如果没有这样做(常见问题解答没有提供明确的答案),我将更新这个3年的问题

解决方法:

基于视图的过滤绝对是最佳选择.您可以使用类似我在下面编写的示例.过滤树时的另一种常见做法是在过滤树时切换到列表视图,因为列表不需要您显示需要显示其后代的隐藏节点.

这是绝对可怕的代码(我试图在刚刚鞭打它的时候削减每一个角落),但它应该足以让你开始.只需在搜索框中键入您的查询,然后按Enter键,它将过滤JTree的默认模型. (仅供参考,前90行只是生成的样板和布局代码.)

package com.example.tree;

import java.awt.BorderLayout;

public class FilteredJTreeExample extends JFrame {

    private JPanel contentPane;
    private JTextField textField;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    FilteredJTreeExample frame = new FilteredJTreeExample();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public FilteredJTreeExample() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        JPanel panel = new JPanel();
        contentPane.add(panel, BorderLayout.NORTH);
        GridBagLayout gbl_panel = new GridBagLayout();
        gbl_panel.columnWidths = new int[]{34, 116, 0};
        gbl_panel.rowHeights = new int[]{22, 0};
        gbl_panel.columnWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
        gbl_panel.rowWeights = new double[]{0.0, Double.MIN_VALUE};
        panel.setLayout(gbl_panel);

        JLabel lblFilter = new JLabel("Filter:");
        GridBagConstraints gbc_lblFilter = new GridBagConstraints();
        gbc_lblFilter.anchor = GridBagConstraints.WEST;
        gbc_lblFilter.insets = new Insets(0, 0, 0, 5);
        gbc_lblFilter.gridx = 0;
        gbc_lblFilter.gridy = 0;
        panel.add(lblFilter, gbc_lblFilter);

        JScrollPane scrollPane = new JScrollPane();
        contentPane.add(scrollPane, BorderLayout.CENTER);
        final JTree tree = new JTree();
        scrollPane.setViewportView(tree);

        textField = new JTextField();
        GridBagConstraints gbc_textField = new GridBagConstraints();
        gbc_textField.fill = GridBagConstraints.HORIZONTAL;
        gbc_textField.anchor = GridBagConstraints.NORTH;
        gbc_textField.gridx = 1;
        gbc_textField.gridy = 0;
        panel.add(textField, gbc_textField);
        textField.setColumns(10);
        textField.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                TreeModel model = tree.getModel();
                tree.setModel(null);
                tree.setModel(model);
            }
        });

        tree.setCellRenderer(new DefaultTreeCellRenderer() {
            private JLabel lblNull = new JLabel();

            @Override
            public Component getTreeCellRendererComponent(JTree tree, Object value,
                    boolean arg2, boolean arg3, boolean arg4, int arg5, boolean arg6) {

                Component c = super.getTreeCellRendererComponent(tree, value, arg2, arg3, arg4, arg5, arg6);

                DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
                if (matchesFilter(node)) {
                    c.setForeground(Color.BLACK);
                    return c;
                }
                else if (containsMatchingChild(node)) {
                    c.setForeground(Color.GRAY);
                    return c;
                }
                else {
                    return lblNull;
                }
            }

            private boolean matchesFilter(DefaultMutableTreeNode node) {
                return node.toString().contains(textField.getText());
            }

            private boolean containsMatchingChild(DefaultMutableTreeNode node) {
                Enumeration<DefaultMutableTreeNode> e = node.breadthFirstEnumeration();
                while (e.hasMoreElements()) {
                    if (matchesFilter(e.nextElement())) {
                        return true;
                    }
                }

                return false;
            }
        });
    }

}

当你真实地实现它时,你可能想要创建自己的TreeNode和TreeCellRenderer实现,使用一个不那么愚蠢的方法来触发更新,并遵循MVC分离.请注意,“隐藏”节点仍然呈现,但它们太小,以至于您无法看到它们.但是,如果您使用箭头键导航树,您会注意到它们仍在那里.如果你只是需要一些有用的东西,这可能就足够了.

编辑

以下是Mac OS中未过滤和过滤的树版本的屏幕截图,显示在Mac OS中可以看到空白:

标签:jtree,swingx,java,swing
来源: https://codeday.me/bug/20190923/1815722.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有