• JTree实现文件树


    这篇文章介绍的内容其实跟TWaver的组件没有任何关系,但是个人觉得还是挺有意思的,所以发出来共享一下。这个文件树(如下图)完全基于swing的JTree组件实现,先看一下最后我们完成的效果:

    运行截图:


    功能介绍:


    • 树状呈现文件系统结构
    • 文件的图标应该使用系统图标
    • 鼠标滑过时改变当前节点的背景色(如图中"Windows"节点的砖红色背景)

    先看一下类结构:

    • FileTreeTest 程序入口
    • FileTree 文件树,从JTree继承
    • FileNode 封装的文件节点,包括文件名,文件图标和实际的File类及其它标识
    • FileTreeRenderer 定制的节点渲染器,从DefaultTreeCellRenderer继承
    • FileTreeModel 定制的TreeModel,从DefaultTreeModel继承

    考虑到系统文件会很多,在程序开始就初始化整个树是不现实的,所以我采取一种延迟加载的策略,只有当要展开某个节点的时候,才去初始化它的子节点,在FileTree的构造里加一个监听:

    addTreeWillExpandListener(new TreeWillExpandListener() {
                @Override
                public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
                    DefaultMutableTreeNode lastTreeNode =
    (DefaultMutableTreeNode) event.getPath().getLastPathComponent();
                    FileNode fileNode = (FileNode) lastTreeNode.getUserObject();
                    if (!fileNode.isInit) {
                        File[] files;
                        if (fileNode.isDummyRoot) {
                            files = fileSystemView.getRoots();
                        } else {
                            files = fileSystemView.getFiles(
                                    ((FileNode) lastTreeNode.getUserObject()).file,
                                    false);
                        }
                        for (int i = 0; i < files.length; i++) {
                           //文件名和图标都是通过fileSystemView得到
                            FileNode childFileNode = new FileNode(
                                    fileSystemView.getSystemDisplayName(files[i]),
                                    fileSystemView.getSystemIcon(files[i]), files[i],
                                    false);
                            DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(childFileNode);
                            lastTreeNode.add(childTreeNode);
                        }
                        //通知模型节点发生变化
                        DefaultTreeModel treeModel1 = (DefaultTreeModel) getModel();
                        treeModel1.nodeStructureChanged(lastTreeNode);
                    }
                    //更改标识,避免重复加载
                    fileNode.isInit = true;
                }
                @Override
                public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
    
                }
            });

    当然这种方式需要TableModel的配合,我重载了DefaultTreeModel,在构造里初始化根节点,然后重载isLeaf方法,具体代码可以下载附件查看。

    接下来思考一下鼠标滑过改变背景色怎么实现。

    写这段代码的时候,我想起来了我刚学Renderer的时候的一个错误的认识:误以为每个节点都有一个Renderer并且妄图在Renderer上加监听!在此强调一下:Renderer只是一个渲染器,要显示节点的时候,JTree就调用它渲染并画到屏幕上,但是无论有多少节点,一个JTree只有一个Renderer!

    Renderer上加监听行不通,我们就转换一下思路,在JTree上加鼠标move监听,然后repaint鼠标所在的节点。

    addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
    //获得鼠标所在的TreePath
                    TreePath path=getPathForLocation(e.getX(), e.getY());
    
    //计算repaint的区域并repaint JTree
                    if(path!=null){
                        if(mouseInPath!=null){
                            Rectangle oldRect=getPathBounds(mouseInPath);
                            mouseInPath=path;
                            repaint(getPathBounds(path).union(oldRect));
                        }else{
                            mouseInPath=path;
                            Rectangle bounds=getPathBounds(mouseInPath);
                            repaint(bounds);
                        }
                    }else if(mouseInPath!=null){
                        Rectangle oldRect=getPathBounds(mouseInPath);
                        mouseInPath=null;
                        repaint(oldRect);
                    }
                }
            });

    需要在JTree中保存鼠标滑过的TreePath(mouseInPath),这样在Renderer中才可以改变mouseInPath的背景色

    FileTree fileTree=(FileTree)tree;
            JLabel label= (JLabel) super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);
    
            DefaultMutableTreeNode node=(DefaultMutableTreeNode)value;
            FileNode fileNode=(FileNode)node.getUserObject();
            label.setText(fileNode.name);
            label.setIcon(fileNode.icon);
    
            label.setOpaque(false);
    //如果当前渲染的节点就是鼠标滑过的节点,改变背景色
            if(fileTree.mouseInPath!=null&&
                    fileTree.mouseInPath.getLastPathComponent().equals(value)){
                label.setOpaque(true);
                label.setBackground(new Color(255,0,0,90));
            }
            return label;

    至此这个文件树就写完了!全部代码在附件,有兴趣的同学可以下载看看,也希望看过的同学有好的想法来交流一下。 附件:见原文最下方

  • 相关阅读:
    HTML5 文件处理之FileAPI简介整理
    HTML5 TypeArray和Unicode 字符之间转换
    HTML5 ArrayBufferView之DataView
    HTML5 Blob与ArrayBuffer、TypeArray和字符串String之间转换
    JavaScript Unicode字符操作
    HTML5 类型数组TypeArray(一)
    HTML之Data URL(转)
    Wpf TextChanged事件导致死循环,事件触发循环问题
    JavaWeb学习笔记:ServletConfig()和ServletContext()
    Effective Java读书笔记
  • 原文地址:https://www.cnblogs.com/twaver/p/2754855.html
Copyright © 2020-2023  润新知