TWaver - 專注UI技術(shù)

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

          JTree實(shí)現(xiàn)文件樹

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

          運(yùn)行截圖:



          功能介紹:

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

           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                        //文件名和圖標(biāo)都是通過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                     //通知模型節(jié)點(diǎn)發(fā)生變化
          26                     DefaultTreeModel treeModel1 = (DefaultTreeModel) getModel();
          27                     treeModel1.nodeStructureChanged(lastTreeNode);
          28                 }
          29                 //更改標(biāo)識(shí),避免重復(fù)加載
          30                 fileNode.isInit = true;
          31             }
          32             @Override
          33             public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
          34 
          35             }
          36         });

          當(dāng)然這種方式需要TableModel的配合,我重載了DefaultTreeModel,在構(gòu)造里初始化根節(jié)點(diǎn),然后重載isLeaf方法,具體代碼可以下載附件查看。

          接下來思考一下鼠標(biāo)滑過改變背景色怎么實(shí)現(xiàn)。
          寫這段代碼的時(shí)候,我想起來了我剛學(xué)Renderer的時(shí)候的一個(gè)錯(cuò)誤的認(rèn)識(shí):誤以為每個(gè)節(jié)點(diǎn)都有一個(gè)Renderer并且妄圖在Renderer上加監(jiān)聽!在此強(qiáng)調(diào)一下:Renderer只是一個(gè)渲染器,要顯示節(jié)點(diǎn)的時(shí)候,JTree就調(diào)用它渲染并畫到屏幕上,但是無論有多少節(jié)點(diǎn),一個(gè)JTree只有一個(gè)Renderer!
          Renderer上加監(jiān)聽行不通,我們就轉(zhuǎn)換一下思路,在JTree上加鼠標(biāo)move監(jiān)聽,然后repaint鼠標(biāo)所在的節(jié)點(diǎn)。

           1 addMouseMotionListener(new MouseAdapter() {
           2             @Override
           3             public void mouseMoved(MouseEvent e) {
           4 //獲得鼠標(biāo)所在的TreePath
           5                 TreePath path=getPathForLocation(e.getX(), e.getY());
           6 
           7 //計(jì)算repaint的區(qū)域并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中保存鼠標(biāo)滑過的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 //如果當(dāng)前渲染的節(jié)點(diǎn)就是鼠標(biāo)滑過的節(jié)點(diǎn),改變背景色
          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;

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

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 常熟市| 长治市| 台中市| 衢州市| 巍山| 防城港市| 巴东县| 镇安县| 石门县| 五峰| 庆元县| 凤凰县| 丹棱县| 镇安县| 赞皇县| 辽源市| 清水河县| 屏南县| 启东市| 青铜峡市| 汉阴县| 南川市| 凌海市| 屏东市| 东兰县| 青阳县| 崇信县| 岳西县| 凤庆县| 松江区| 陆川县| 穆棱市| 巫山县| 囊谦县| 唐河县| 株洲市| 麟游县| 阜平县| 山东| 外汇| 廊坊市|