TWaver - 專注UI技術

          http://twaver.servasoft.com/
          posts - 171, comments - 191, trackbacks - 0, articles - 2
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          JTree實現文件樹

          Posted on 2012-11-02 15:20 TWaver 閱讀(2484) 評論(0)  編輯  收藏
          這篇文章介紹的內容其實跟TWaver的組件沒有任何關系,但是個人覺得還是挺有意思的,所以發出來共享一下。這個文件樹(如下圖)完全基于swing的JTree組件實現,先看一下最后我們完成的效果:

          運行截圖:



          功能介紹:

          • 樹狀呈現文件系統結構
          • 文件的圖標應該使用系統圖標
          • 鼠標滑過時改變當前節點的背景色(如圖中"Windows"節點的磚紅色背景)
          先看一下類結構:
          • FileTreeTest 程序入口
          • FileTree 文件樹,從JTree繼承
          • FileNode 封裝的文件節點,包括文件名,文件圖標和實際的File類及其它標識
          • FileTreeRenderer 定制的節點渲染器,從DefaultTreeCellRenderer繼承
          • FileTreeModel 定制的TreeModel,從DefaultTreeModel繼承
          考慮到系統文件會很多,在程序開始就初始化整個樹是不現實的,所以我采取一種延遲加載的策略,只有當要展開某個節點的時候,才去初始化它的子節點,在FileTree的構造里加一個監聽:

           1 addTreeWillExpandListener(new TreeWillExpandListener() {
           2             @Override
           3             public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
           4                 DefaultMutableTreeNode lastTreeNode =
           5 (DefaultMutableTreeNode) event.getPath().getLastPathComponent();
           6                 FileNode fileNode = (FileNode) lastTreeNode.getUserObject();
           7                 if (!fileNode.isInit) {
           8                     File[] files;
           9                     if (fileNode.isDummyRoot) {
          10                         files = fileSystemView.getRoots();
          11                     } else {
          12                         files = fileSystemView.getFiles(
          13                                 ((FileNode) lastTreeNode.getUserObject()).file,
          14                                 false);
          15                     }
          16                     for (int i = 0; i < files.length; i++) {
          17                        //文件名和圖標都是通過fileSystemView得到
          18                         FileNode childFileNode = new FileNode(
          19                                 fileSystemView.getSystemDisplayName(files[i]),
          20                                 fileSystemView.getSystemIcon(files[i]), files[i],
          21                                 false);
          22                         DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(childFileNode);
          23                         lastTreeNode.add(childTreeNode);
          24                     }
          25                     //通知模型節點發生變化
          26                     DefaultTreeModel treeModel1 = (DefaultTreeModel) getModel();
          27                     treeModel1.nodeStructureChanged(lastTreeNode);
          28                 }
          29                 //更改標識,避免重復加載
          30                 fileNode.isInit = true;
          31             }
          32             @Override
          33             public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
          34 
          35             }
          36         });

          當然這種方式需要TableModel的配合,我重載了DefaultTreeModel,在構造里初始化根節點,然后重載isLeaf方法,具體代碼可以下載附件查看。

          接下來思考一下鼠標滑過改變背景色怎么實現。
          寫這段代碼的時候,我想起來了我剛學Renderer的時候的一個錯誤的認識:誤以為每個節點都有一個Renderer并且妄圖在Renderer上加監聽!在此強調一下:Renderer只是一個渲染器,要顯示節點的時候,JTree就調用它渲染并畫到屏幕上,但是無論有多少節點,一個JTree只有一個Renderer!
          Renderer上加監聽行不通,我們就轉換一下思路,在JTree上加鼠標move監聽,然后repaint鼠標所在的節點。

           1 addMouseMotionListener(new MouseAdapter() {
           2             @Override
           3             public void mouseMoved(MouseEvent e) {
           4 //獲得鼠標所在的TreePath
           5                 TreePath path=getPathForLocation(e.getX(), e.getY());
           6 
           7 //計算repaint的區域并repaint JTree
           8                 if(path!=null){
           9                     if(mouseInPath!=null){
          10                         Rectangle oldRect=getPathBounds(mouseInPath);
          11                         mouseInPath=path;
          12                         repaint(getPathBounds(path).union(oldRect));
          13                     }else{
          14                         mouseInPath=path;
          15                         Rectangle bounds=getPathBounds(mouseInPath);
          16                         repaint(bounds);
          17                     }
          18                 }else if(mouseInPath!=null){
          19                     Rectangle oldRect=getPathBounds(mouseInPath);
          20                     mouseInPath=null;
          21                     repaint(oldRect);
          22                 }
          23             }
          24         });

          需要在JTree中保存鼠標滑過的TreePath(mouseInPath),這樣在Renderer中才可以改變mouseInPath的背景色

           1 FileTree fileTree=(FileTree)tree;
           2         JLabel label= (JLabel) super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);
           3 
           4         DefaultMutableTreeNode node=(DefaultMutableTreeNode)value;
           5         FileNode fileNode=(FileNode)node.getUserObject();
           6         label.setText(fileNode.name);
           7         label.setIcon(fileNode.icon);
           8 
           9         label.setOpaque(false);
          10 //如果當前渲染的節點就是鼠標滑過的節點,改變背景色
          11         if(fileTree.mouseInPath!=null&&
          12                 fileTree.mouseInPath.getLastPathComponent().equals(value)){
          13             label.setOpaque(true);
          14             label.setBackground(new Color(255,0,0,90));
          15         }
          16         return label;

          至此這個文件樹就寫完了!全部代碼在附件,有興趣的同學可以下載看看,也希望看過的同學有好的想法來交流一下。 附件:見原文最下方

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 上思县| 龙山县| 宁安市| 谢通门县| 上虞市| 肃宁县| 突泉县| 温宿县| 西华县| 亚东县| 玛纳斯县| 虞城县| 梁平县| 安康市| 晋中市| 太原市| 延吉市| 肇州县| 大庆市| 镶黄旗| 吉木萨尔县| 淮安市| 伊金霍洛旗| 和顺县| 商南县| 大足县| 龙泉市| 太原市| 揭西县| 兴和县| 珠海市| 巴彦县| 龙里县| 乾安县| 炎陵县| 城固县| 宁蒗| 嫩江县| 华安县| 永新县| 临湘市|