积微成著 不积跬步,无以至千里

首页   >   web开发   >   JTree的第三次优化详细教程

JTree的第三次优化详细教程

关于jtree的代码二次优化,开始觉着很完美,可是后来仔细一想,好像还是没有脱离第一次优化时的思路,在渲染当前节点时,恢复之前的节点,为什么非要循环jtree来处理呢?

如果说jtree有成百上千个节点,那么每次循环,性能肯定好不到哪里去,所以还需要第三次优化。

思路:定义变量来记录之前的节点,每次变动,只更新这两个指定的节点

好处:不用每次都刷新整颗jtree,也不需要在自定义node中增加字段来标记选中(这个字段开始设计就是为了在循环刷新整颗jtree的时候使用)

前两次优化中,描述已经说得很多了,这次就不再赘述,直接贴代码;

由于只是精简了代码,所以效果图还是一样的。

JTreeFrame.java

package com.wolffy.frame;

import com.wolffy.node.MyTreeNode;
import com.wolffy.ui.MyTreeUI;
import com.wolffy.util.ImgUtils;
import com.wolffy.util.TreeUtils;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.WindowConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;


/**
 * Created by SongFei on 2017/10/24.
 */
public class JTreeFrame extends JFrame {

    private static final long serialVersionUID = 8632851951749045685L;

    /**
     * 鼠标滑过
     */
    private Color HOVER_COLOR = new Color(200, 200, 200, 100);

    /**
     * 鼠标点击
     */
    private Color SELECT_COLOR = new Color(160, 160, 160, 100);

    private JPanel jPanel;

    private JTree jTree;

    private DefaultMutableTreeNode root;
    private DefaultTreeModel model;

    private MyTreeNode selectNode;
    private MyTreeNode hoverNode;

    public JTreeFrame() {
        initGUI();
    }

    private void initGUI() {
        setSize(700, 575);
        //setUndecorated(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        jPanel = new JPanel();
        getContentPane().add(jPanel, BorderLayout.CENTER);

        root = new DefaultMutableTreeNode();
        model = new DefaultTreeModel(root);

        for (int i = 1; i <= 3; i++) {
            MyTreeNode cate = new MyTreeNode(ImgUtils.getIcon("arrow_left.png"), "我的分组" + i);
            for (int j = 1; j <= 3; j++) {
                MyTreeNode node = new MyTreeNode(ImgUtils.getIcon("avatar.png"), "好友" + i + "-" + j, "人生若只如初见");
                cate.add(node);
            }
            root.add(cate);
        }

        jTree = new JTree(model);
        jTree.setUI(new MyTreeUI());

        jTree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                if (hoverNode == null) {
                    return;
                }
                if (hoverNode != selectNode) {
                    TreeUtils.restoreNodeColor(model, hoverNode);
                }
                hoverNode = null;
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                TreePath path = jTree.getSelectionPath();
                if (path == null) {
                    return;
                }
                MyTreeNode node = (MyTreeNode) path.getLastPathComponent();
                if (node == null) {
                    return;
                }
                // 除了好友节点,其他节点都没有点击选中功能
                if (node.getLevel() != 2) {
                    return;
                }
                // 避免重复点击
                if (node == selectNode) {
                    return;
                }
                TreeUtils.restoreNodeColor(model, selectNode);
                TreeUtils.setNodeColor(model, node, SELECT_COLOR);
                selectNode = node;
            }
        });

        jTree.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                TreePath path = jTree.getPathForLocation(e.getX(), e.getY());
                if (path == null) {
                    return;
                }
                MyTreeNode node = (MyTreeNode) path.getLastPathComponent();
                if (node == null) {
                    return;
                }
                // 同一个节点,避免重复hover
                if (node == hoverNode) {
                    return;
                }
                // 点击了一个节点之后,select == hover,此时再次滑动时就会导致将select的颜色变成hover的颜色了
                // select的权重高,已经select了,就不再hover
                if (hoverNode != selectNode) {
                    TreeUtils.restoreNodeColor(model, hoverNode);
                }
                // hover到了select节点,就不再hover
                if (node == selectNode) {
                    hoverNode = node;// 必须记录一下,否则重复滑动不了
                    return;
                }
                TreeUtils.setNodeColor(model, node, HOVER_COLOR);
                hoverNode = node;
            }
        });

        jPanel.add(jTree);
    }

    public static void main(String[] args) {
        JTreeFrame jTreeFrame = new JTreeFrame();
        jTreeFrame.setVisible(true);
    }

}

TreeUtils.java

package com.wolffy.util;

import com.wolffy.node.MyTreeNode;

import javax.swing.JPanel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.Color;

/**
 * Created by SongFei on 2017/11/6.
 */
public class TreeUtils {

    /**
     * 设置Node背景颜色
     *
     * @param model 模型,需要用它来刷新jtree
     * @param node  自定义的MyTreeNode节点
     * @param color 颜色
     */
    public static void setNodeColor(DefaultTreeModel model, MyTreeNode node, Color color) {
        if (model == null || node == null) {
            return;
        }

        JPanel panel = null;

        if (node.getLevel() == 1) {
            panel = (JPanel) node.getGroupView();
        }

        if (node.getLevel() == 2) {
            panel = (JPanel) node.getBuddyView();
        }

        if (panel != null) {
            panel.setBackground(color);
            model.reload(node);
        }
    }

    /**
     * 重置Node节点的Color
     *
     * @param model 模型
     * @param node  自定义Node
     */
    public static void restoreNodeColor(DefaultTreeModel model, MyTreeNode node) {
        if (model == null || node == null) {
            return;
        }
        if (node.getLevel() == 1) {
            node.getGroupView().setBackground(null);
        }
        if (node.getLevel() == 2) {
            node.getBuddyView().setBackground(null);
        }
        model.reload(node);
    }

}

MyTreeNode.java

package com.wolffy.node;

import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.Component;
import java.awt.Dimension;

/**
 * Created by SongFei on 2017/11/6.
 */
public class MyTreeNode extends DefaultMutableTreeNode {

    private static final long serialVersionUID = 1007068847268622569L;

    /**
     * 图片
     */
    private Icon icon;

    /**
     * 文字
     */
    private String name;

    /**
     * 签名
     */
    private String sign;

    private JPanel groupPanel;
    private JPanel buddyPanel;

    private JLabel iconLabel;
    private JLabel nameLabel;
    private JLabel signLabel;

    public MyTreeNode() {
    }

    /**
     * 初始化分组节点
     *
     * @param name 名称
     */
    public MyTreeNode(Icon icon, String name) {
        this.icon = icon;
        this.name = name;
        // 初始化UI
        initCateGUI();
    }

    /**
     * 初始化好友节点
     *
     * @param icon 头像
     * @param nick 昵称
     * @param sign 签名
     */
    public MyTreeNode(Icon icon, String nick, String sign) {
        this.icon = icon;
        this.name = nick;
        this.sign = sign;
        // 初始化UI
        initNodeGUI();
    }

    /**
     * 自定义分组UI
     */
    private void initCateGUI() {
        groupPanel = new JPanel();
        groupPanel.setLayout(null);
//		groupPanel.setOpaque(false);
        // 这里大家注意,当我们写好UI之后可能会发现他的颜色不太对,
        // 这时候千万不要用上面那句,不然当我们想再次改变其颜色的时候,就生效不了
        // 红绿蓝分别为255的这个颜色趋近于透明,我们可以用它来代替setOpaque
//		groupPanel.setBackground(new Color(255,255,255));
        // 突然发现置成null也可以
        groupPanel.setBackground(null);
        groupPanel.setPreferredSize(new Dimension(300, 25));
//		groupPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));

        iconLabel = new JLabel(icon);
        iconLabel.setBounds(6, 5, 20, 16);
        groupPanel.add(iconLabel);

        nameLabel = new JLabel(name);
        nameLabel.setBounds(23, 0, 132, 28);
        groupPanel.add(nameLabel);
    }

    /**
     * 自定义好友UI
     */
    private void initNodeGUI() {
        buddyPanel = new JPanel();
        buddyPanel.setLayout(null);
        buddyPanel.setBackground(null);
        buddyPanel.setPreferredSize(new Dimension(300, 50));
//		buddyPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));

        iconLabel = new JLabel(icon);
        iconLabel.setBounds(8, 4, 42, 42);
        buddyPanel.add(iconLabel);

        nameLabel = new JLabel(name);
        nameLabel.setBounds(59, 5, 132, 19);
        buddyPanel.add(nameLabel);

        signLabel = new JLabel(sign);
        signLabel.setBounds(59, 28, 132, 17);
        buddyPanel.add(signLabel);
    }

    /**
     * 将自定义UI返回给渲染器	<br/>
     * 供渲染器调用,返回的必须是一个Component
     *
     * @return
     */
    public Component getGroupView() {
        return groupPanel;
    }

    /**
     * 将自定义UI返回给渲染器	<br/>
     * 供渲染器调用,返回的必须是一个Component
     *
     * @return
     */
    public Component getBuddyView() {
        return buddyPanel;
    }

    public JLabel getIconLabel() {
        return iconLabel;
    }

    public JLabel getNameLabel() {
        return nameLabel;
    }

    public JLabel getSignLabel() {
        return signLabel;
    }

    public Icon getIcon() {
        return icon;
    }

    public void setIcon(Icon icon) {
        this.icon = icon;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

}

几个主要改动点:MouseListener中的逻辑、MyTreeNode的字段精简、TeeUtils代码精简。

MyTreeUI没有改动,大家可以直接用上一篇文章(http://jiweichengzhu.com/article/5ff1be1e8abe463794aa1011b4bcff96)中的代码!

QQ群:积微成著官方群(686430774),验证消息:积微成著

站长Q:1347384268(加好友请注明来意)

分享到:

欢迎分享本文,转载请注明出处!

作者:不忘初心

发布时间:2017-11-08

永久地址:http://www.jiweichengzhu.com/article/0de2cae621fb4ecb9f0a98c8f856aedb