IDEA Plugin---种一棵优雅的JTree

713 阅读2分钟

最近笔者在写一个用来Json格式化的IDEA插件,因为Swing的资料相对比较少,自己也没怎么学过,最后实现起来属实费了一些功夫,在此记录一下。

创建

public static void main(String[] args) {
    //创建节点
    DefaultMutableTreeNode defaultMutableTreeNode = new DefaultMutableTreeNode("this is parent");
    DefaultMutableTreeNode childrenNode = new DefaultMutableTreeNode("son");
    DefaultMutableTreeNode grandChildrenNode = new DefaultMutableTreeNode("grandson");
    DefaultMutableTreeNode anotherNode = new DefaultMutableTreeNode("this is another node");
    //添加子节点
    defaultMutableTreeNode.add(childrenNode);
    //子节点添加孙节点
    childrenNode.add(grandChildrenNode);
    defaultMutableTreeNode.add(anotherNode);
    JTree jTree = new JTree(defaultMutableTreeNode);

    JFrame jFrame = new JFrame();
    jFrame.add(jTree);
    jFrame.setVisible(true);
    jFrame.setSize(840, 270);
    //关闭窗口自动结束程序
    jFrame.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent we) {
            System.exit(0);
        }
    });
}

通过上面的代码,就可以快速创建一个JTree了,启动之后就是下面这个样子

image.png

展开合并监听事件

可以通过添加展开合并的监听事件(树膨胀监听器?)来实现展开或者合并树时,增加一些自定义功能

jTree.addTreeExpansionListener(new TreeExpansionListener() {
    //展开事件
    @Override
    public void treeExpanded(TreeExpansionEvent event) {
        System.out.println("我展开的是" + event.getPath().getLastPathComponent());
    }
    //收起事件
    @Override
    public void treeCollapsed(TreeExpansionEvent event) {
        System.out.println("我收起的是" + event.getPath().getLastPathComponent());

    }
});

event.getPath().getLastPathComponent()可以获取到当前展开的节点

刷新UI

有时我们需要动态添加节点,在添加之后需要调用刷新UI的api才会生效

defaultMutableTreeNode.add(new DefaultMutableTreeNode("i am a new one "));
//只有加上这行代码,才会显示出新的节点
jTree.updateUI();

⚠️ 注意:如果调用updateUI()是在其他线程中,需要使用SwingUtilities.invokeLater()

jTree.addTreeExpansionListener(new TreeExpansionListener() {
    @Override
    public void treeExpanded(TreeExpansionEvent event) {
        System.out.println("我展开的是" + event.getPath().getLastPathComponent());
        //这里不会报错
        SwingUtilities.invokeLater(() -> jTree.updateUI());
    }

    @Override
    public void treeCollapsed(TreeExpansionEvent event) {
        System.out.println("我收起的是" + event.getPath().getLastPathComponent());
        //这里会抛出空指针异常
        jTree.updateUI()

    }
});

换皮肤

如果不满足于默认的样式,比如节点的默认图标,怎么看怎么像一个文件管理系统,当我用来做一个json格式化工具时,就会怪怪的,这个时候就可以用到自定义渲染

创建自定义渲染器

继承DefaultTreeCellRenderer后,重写getTreeCellRendererComponent这个方法。此时,如果不想要这个很像文件管理器的图标,就可以像下面这样把图标取消掉

class MyRenderer extends DefaultTreeCellRenderer {

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

        Component component = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
        setIcon(null);
        return component;
    }
}

image.png

如果只是用来去除图标的话,还是有些大材小用了。上面的方法返回了一个Compnent,这时就可以制作一些自定义组件了

比如,可以返回一些按钮

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

    Component component = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
    setIcon(null);
    return new JButton(value.toString());
}

image.png

一些文本框

image.png

又或是。。。一些五颜六色的东西

WechatIMG33146.png

本文的内容到这就结束了,如果觉得有帮助别忘了点个赞呀!