<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    zeyuphoenix

    愿我愛的人快樂,愿愛我的人快樂,為了這些,我愿意不快樂.

    JTree--樹(節點渲染和資源管理器加載)(二)

    這次我們用樹實現一個比較綜合的例子,做一個類似Windows的資源管理器,先看Windows,如下圖:

    接著就是我們的實現了,路是一步一步走的,先看最基礎的實現,這個例子是我在網上看到的,雖然簡單,起碼是一種思路:

    效果如下圖:

    先說說這個實現的思路吧,首先創建樹,再創建一個根節點,然后取得盤符,把盤符放置在根節點下面,然后增加樹的監聽,當樹的節點展開時,取得當前節點下的所有文件和文件夾,加入到節點下,刷新樹,展開到指定位置就可以了.

    先是創建根節點的:

    public DefaultMutableTreeNode createRootNode(){ 

          File dir = new File("."); 

          DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(ROOT_NAME); 

          for(int i = 0; i < dir.listRoots().length; i++){ 

              if(dir.listRoots()[i].isDirectory()){ 

                  String rootPath = dir.listRoots()[i].getPath(); 

                  this.treeNode = new DefaultMutableTreeNode(rootPath); 

                  rootNode.add(this.treeNode); 

                  this.treeNode = null

              } 

          } 

            return rootNode; 

        }

    然后是增加監聽,這里我們監聽展開事件:

    this.tree.addTreeExpansionListener(this); 

    然后是處理事件:

        @Override

    publicvoid treeExpanded(TreeExpansionEvent event) { 

    先取得選擇的節點對象:

    this.selectNode

    =(DefaultMutableTreeNode)event.getPath().getLastPathComponent();

    然后取得節點的絕對路徑:

        String path = event.getPath().toString(); 

    然后根據路徑在節點下添加子節點:

        publicvoid addTreeNode(DefaultMutableTreeNode node, File dir) {

           if (node == null || dir == null) {

               return;

           }

           if (!dir.isDirectory()) {

               return;

           }

           if (!node.isRoot()) {

               // get all files in node

               File file[] = dir.listFiles();

               for (int i = 0; i < file.length; i++) {

                  // hidden is not show

                  if (file[i].isDirectory() && !file[i].isHidden()) {

                      // create node

                      this.treeNode = new DefaultMutableTreeNode(dir.list()[i]);

                      // add to tree

                      ((DefaultTreeModel) this.jt.getModel()).insertNodeInto(

                             treeNode, node, node.getChildCount());

                      this.treeNode = null;

                  }

               }

           }

        }

    同樣的收起事件也要處理:

        @Override

    publicvoid treeCollapsed(TreeExpansionEvent event) { 

    最后把樹放置在JScrollPane上就可以了.

    this.jscroolpane.setViewportView(this.tree); 

    這樣一個簡單的資源管理樹就完成了,下面我們說說它的問題:

         圖片和外觀和Windows相差太大

    這個我們可以通過設置L&F和通過前面寫的Renderer那樣設置新的圖片解決,不是大問題.

         文件夾里文件多時展開會很慢,會導致界面假死

    這個我們可以自己寫一個緩加載的TreeNode,讓它繼承于DefaultMutableTreeNode,在它里面定義加載標示,然后使用SwingWorker或者多線程方式使Tree平穩加載,雖然麻煩,但是也可以解決.

         Tree點擊假死時,用戶會以為出現問題,胡亂點擊會加載多個事件

    這個問題其實是Swing事件機制的問題,其實是沒辦法解決的,因為總會存在耗時的操作的,不等待是不可能的.但我們可以做更好的用戶體驗來避免這個問題,這里我想到的解決辦法是在Tree上繪制一層GlassPane,屏蔽所有事件,提示用戶,等加載完成后,取消GlassPane界面.

         只有我的電腦的基本文件,沒有網上鄰居之類的

    這個問題很難解決,涉及到網上鄰居就存在網絡的問題了,還需要網絡連接和掃描,開始我的思路是使用Apachecommons-client,后來發現有人給出了更好的辦法,使用JavaJFileChooser,Java已經實現了很多我們需要實現的.

         取得的資源管理樹的子目錄是亂序的

    這個很好解決,使我們的TreeNode實現Comparable接口就可以了.

    為了解決這五個問題我們做的改進版:

    首先我們解決問題一,看看我們的代碼:

    節點的圖片的樣式問題我們可以設置Renderer,又因為這些圖片可以在JFileChooserUI中取得,我們先參照JFileChooserUI做一個FileView:

        // ***********************

        // * FileView operations *

        // ***********************

        protectedclass BasicFileView extends FileView {

    復寫它的方法:

           @Override

           public String getName(File f) {

               // Note: Returns display name rather than file name

               String fileName = null;

               if (f != null) {

                  fileName = chooser.getFileSystemView().getSystemDisplayName(f);

               }

               return fileName;

           }

    這個是顯示名字.

           @Override

           public String getDescription(File f) {

               return f.getName();

           }

    這個是描述

           @Override

           public String getTypeDescription(File f) {

               String type = chooser.getFileSystemView().getSystemTypeDescription(

                      f);

               if (type == null) {

                  if (f.isDirectory()) {

                      type = directoryDescriptionText;

                  } else {

                      type = fileDescriptionText;

                  }

               }

               return type;

           }

    這個是文件類別

           @Override

           public Icon getIcon(File f) {

    這個是圖片表示.

    這樣我們構建這個FileView之后我們需要的圖片和名字就都可以取得了.

    然后是我們的Renderer了:

    privateclass FileSystemTreeRenderer extends DefaultTreeCellRenderer {

    復寫它的方法,設置我們從FileView取得圖片和名字:

    @Override

    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row,

         boolean hasFocus) {

         setText(getFileView(chooser).getName(node.getFile()));

         setIcon(getFileView(chooser).getIcon(node.getFile()));

    然后設置到樹上:

         tree.setCellRenderer(new FileSystemTreeRenderer());

    看看效果:

    是不是和Windows的很接近了,設置L&F,如下圖:

    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

    然后解決問題二,我們不能用樹的原始節點了,用我們自己構造的,繼承于它:

    publicabstractclass LazyMutableTreeNode extends DefaultMutableTreeNode {

    增加一個屬性:

        /** is node load. */

        privatebooleanloaded = false;

    提供一個虛方法給子類實現:

        protectedabstractvoid loadChildren();

    然后是我們的實現:

    privateclass FileTreeNode extends LazyMutableTreeNode {

    復寫它的方法,load不允許加載:

            @Override

           publicboolean isLeaf() {

               if (!isLoaded()) {

                  returnfalse;

               } else {

                  returnsuper.isLeaf();

               }

           }

    還有它的現實名字:

           @Override

           public String toString() {

               returnchooser.getFileSystemView().getSystemDisplayName(

                      (File) getUserObject());

            }

    實現虛方法:

        @Override

           protectedvoid loadChildren() {

               FileTreeNode[] nodes = getChildren();

               for (int i = 0, c = nodes.length; i < c; i++) {

                  add(nodes[i]);

               }

           }

    這樣問題二就解決了,同時也可以在這里解決我們的問題五,使我們的TreeNode實現Comparable接口:

        privateclass FileTreeNode extends LazyMutableTreeNode implements

               Comparable<Object> {

    然后實現方法:

        @Override

           publicint compareTo(Object o) {

               if (!(o instanceof FileTreeNode)) {

                  return 1;

               }

               return getFile().compareTo(((FileTreeNode) o).getFile());

           }

    最后在我們使用時:

           // sort directories, FileTreeNode implements Comparable

           FileTreeNode[] result = (FileTreeNode[]) nodes

                  .toArray(new FileTreeNode[0]);

           Arrays.sort(result);

    nodes.add(new FileTreeNode(result[i]));

    這樣我們加入的節點文件夾就都是排序的了.

    然后我們解決問題四,三比較麻煩留在最后:

    構建這個組件時,我們先構建JFileChooser

    JFileChooser chooser = new JFileChooser();

    增加監聽:

        protectedvoid installListeners() {

           tree.addTreeSelectionListener(new SelectionListener());

           chooser.getActionMap().put("refreshTree", new UpdateAction());

            chooser.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(

                  KeyStroke.getKeyStroke("F5"), "refreshTree");

           chooser.addPropertyChangeListener(new ChangeListener());

        }

    在監聽中展開樹時,使用JFileChooser的方法:

        /**

         * tree node select change.

         */

        privateclass SelectionListener implements TreeSelectionListener {

           @Override

           publicvoid valueChanged(TreeSelectionEvent e) {

               getApproveSelectionAction()

                      .setEnabled(tree.getSelectionCount() > 0);

               setSelectedFiles();

               // the current directory is the one currently selected

               TreePath currentDirectoryPath = tree.getSelectionPath();

               if (currentDirectoryPath != null) {

                  File currentDirectory = ((FileTreeNode) currentDirectoryPath

                         .getLastPathComponent()).getFile();

                  chooser.setCurrentDirectory(currentDirectory);

               }

           }

        }

    這樣我們所有的目錄結構就不需要自己去循環構建了,使用JFileChooser為我們提供好的就可以了,如下圖,網上鄰居也有了,問題四完成了:

    最后我們來解決問題三,為什么會假死,是因為文件夾多或者網速慢導致的,解決辦法當然是多線程,但是多線程在Swing里容易出現線程不安全,因為它不在ADT,這里我們使用SwingWorker,監聽樹的展開事件:

    tree.addTreeExpansionListener(new TreeExpansion());

    處理它:

        privateclass TreeExpansion implements TreeExpansionListener {

           @Override

           publicvoid treeCollapsed(TreeExpansionEvent event) {

           }

           @Override

           publicvoid treeExpanded(TreeExpansionEvent event) {

               // ensure children gets expanded later

               if (event.getPath() != null) {

               Object lastElement = event.getPath().getLastPathComponent();

                  if (lastElement instanceof FileTreeNode && useNodeQueue)

                      if (((FileTreeNode) lastElement).isLoaded()) {

    慢主要是在這里的處理,我們把它放在SwingWorker里面:

    new WorkerQueue(node, tree, glassPane).execute();

    然后看這個類:

        privatestaticfinalclass WorkerQueue extends

               SwingWorker<Void, FileTreeNode> {

    復寫它的方法,處理我們的TreeNode添加事件:

        @Override

        protected Void doInBackground() throws Exception {

           glassPanel.setVisible(true);

           for (Enumeration<?> e = node.children(); e.hasMoreElements();) {

               publish((FileTreeNode) e.nextElement());

           }

           returnnull;

        }

        @Override

        protectedvoid process(List<FileTreeNode> chunks) {

           for (FileTreeNode fileTreeNode : chunks) {

               fileTreeNode.getChildCount();

           }

        }

        @Override

        protectedvoid done() {

           glassPanel.setVisible(false);

           tree.repaint();

        }

    然后是處理我們在展開節點時屏蔽所有的鼠標點擊并給以用戶提示,這里我們自己繪制一個Component,把它設置為GlassPane,屏蔽所有事件:

    /**

     */

    publicclass GlassPane extends JComponent {

    屏蔽所有事件,只能獲得焦點:

        // blocks all user input

        addMouseListener(new MouseAdapter() {

        });

        addMouseMotionListener(new MouseMotionAdapter() {

        });

        addKeyListener(new KeyAdapter() {

        });

        setFocusTraversalKeysEnabled(false);

        addComponentListener(new ComponentAdapter() {

           publicvoid componentShown(ComponentEvent evt) {

               requestFocusInWindow();

           }

        });

    然后是繪制:

        @Override

        protectedvoid paintComponent(Graphics g) {

    先繪制整體背景:

           // gets the current clipping area

           Rectangle clip = g.getClipBounds();

           // sets a 65% translucent composite

           AlphaComposite alpha = AlphaComposite.SrcOver.derive(0.65f);

           Composite composite = g2.getComposite();

           g2.setComposite(alpha);

           // fills the background

           g2.setColor(getBackground());

           g2.fillRect(clip.x, clip.y, clip.width, clip.height);

           g2.setComposite(composite);

    然后繪制一張提示圖片,本來想繪制一個滾動的等待圖標,實在是沒心情寫了,隨便Google了張圖片放上去了.

        if (image == null) {

           try {

              image = ImageIO.read(getClass().getResource("wait2.jpg"));

           } catch (IOException ex) {

               ex.printStackTrace();

           }

        }

        g.drawImage(image, getWidth() / 2 - 40, getHeight() / 2

           - 80, 120, 120, null);

    通過設置畫面的GlassPane就可以了

        Component glassPane = new GlassPane();

        frame.getRootPane().setGlassPane(glassPane);

    最終效果如下圖:

    到此為止,關于樹的操作基本就完成了,下面再開個專題講下有CheckBoxJTree,至于JTree的拖拽,因為和其它Component基本是一致的,就留在以后拖拽專題一起寫了,總之,JTree還是不算復雜的一個組件.

    posted on 2010-04-22 22:51 zeyuphoenix 閱讀(5425) 評論(11)  編輯  收藏 所屬分類: JTree的使用

    評論

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2010-04-23 08:57 股海e程

    好文章!  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2010-04-24 09:20 羅萊家紡

    你們呢是明年的南方  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2010-04-24 14:18 fivesmallq

    樓主的文章一直在訂閱拜讀。寫的很好  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2010-06-11 15:27 xdelxia

    老大能給我份源碼么,我看得不是很懂啊,763823729@qq.com這是我的郵箱,謝謝老大,請一定要給我份啊,我最近做的項目遇到了個關于圖片的加載問題,我現在解決不了!  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2011-10-01 09:17 bug

    真的很厲害.但由于本人java水平不高.請問能否給分原代碼讓我參考學習呢?我的郵箱1280074964@qq.com 謝謝~  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2011-10-11 15:42 allenxiaomai

    寫的很好呢。能不能發給我一份源代碼讓我仔細學習一下呢?郵箱:476847992@qq.com,謝謝啦。  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2011-10-14 12:29 1788455@qq.com

    你好 能給我一份Swing的源碼么  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二)[未登錄] 2011-10-22 16:46 wei

    寫得很好啊,可以給我一份源碼嗎?我研究了很久,都不知道怎么寫。。謝謝
    jidi123698745@tom.com  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2012-12-06 18:22 真惡心

    你這樣寫,別人拿去怎么用,下載源碼的地方又不能用?什么意思。如果僅僅是自己看的話,那就隱藏起來吧。  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二) 2015-04-05 16:25 張森洋

    請問參考JFileChooser的UI做的那個FileView類怎么寫?  回復  更多評論   

    # re: JTree--樹(節點渲染和資源管理器加載)(二)[未登錄] 2015-11-12 23:03 ch

    能給份 Jtable 、以及Swing 其他組件的代碼 258440352@qq.com  回復  更多評論   

    導航

    <2010年4月>
    28293031123
    45678910
    11121314151617
    18192021222324
    2526272829301
    2345678

    統計

    常用鏈接

    留言簿(52)

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 美女被暴羞羞免费视频| 免费在线观看a级毛片| 一级特黄录像免费播放肥| 亚洲情A成黄在线观看动漫软件 | 亚洲黄网站wwwwww| 国产亚洲精品看片在线观看| 午夜dj免费在线观看| 国产成人精品免费视频动漫| 最近中文字幕大全免费版在线| 美女视频黄频a免费| 亚洲欧洲无码AV不卡在线| 亚洲国产综合自在线另类| 亚洲AV无码一区二区三区DV | 免费精品国自产拍在线播放| 在线观看亚洲AV日韩AV| 亚洲情A成黄在线观看动漫软件| 亚洲视频在线一区二区三区| 亚洲av无码专区国产乱码在线观看| 国产精品亚洲二区在线观看| 亚洲AV日韩精品一区二区三区| 日本黄色免费观看| 免费高清av一区二区三区| 成年在线网站免费观看无广告| 在线看免费观看AV深夜影院| 182tv免费观看在线视频| 免费人成视频在线观看网站| 鲁丝片一区二区三区免费 | 久久亚洲国产中v天仙www| 中文字幕亚洲日本岛国片| a级亚洲片精品久久久久久久 | 麻豆亚洲AV成人无码久久精品 | 国产91免费视频| 国产高清免费视频| 在线观看AV片永久免费| 国产精品久久久久久久久久免费| 免费在线视频你懂的| AA免费观看的1000部电影| 天天干在线免费视频| 国产午夜免费福利红片| 亚洲 无码 在线 专区| 国产成人亚洲综合|