首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Swing 動態載入系統檔案樹:按需讀取解決大量節點效能問題

     編輯:Java 相關知識

問題背景

一次性構建整棵檔案樹的 TreeModel 會阻塞 UI 線程,導致介面凍結。解決方案:採用「懶加載」—— 根節點先顯示,用戶展開資料夾時才讀取該目錄下的子項。

核心設計

  • 自訂節點類 PathNode 繼承 DefaultMutableTreeNode,保存絕對路徑與是否為資料夾。
  • 滑鼠點擊事件中判斷:若為資料夾且 getChildCount()==0,動態讀取磁碟建立子節點並 add()。
  • 使用 TreeCellRenderer 區分資料夾/檔案圖示(展開/收合狀態)。

完整代碼

import javax.swing.*;
import javax.swing.tree.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;

public class SystemFileTree {
    private DefaultTreeModel model;
    private JTree tree;

    public SystemFileTree() {
        JFrame f = new JFrame();
        f.setLayout(new BorderLayout());
        tree = new JTree();
        tree.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) { nodeMouseAction(e); }
        });
        f.add(new JScrollPane(tree), BorderLayout.CENTER);
        f.setBounds(250, 250, 300, 500);
        f.setVisible(true);
    }

    private void nodeMouseAction(MouseEvent e) {
        int row = tree.getRowForLocation(e.getX(), e.getY());
        if (row == -1) return;
        TreePath path = tree.getPathForRow(row);
        PathNode node = (PathNode) path.getLastPathComponent();
        if (node.isFolder() && node.getChildCount() == 0) {
            buildNode(node);
            tree.expandPath(path);
        }
    }

    private PathNode buildNode(PathNode parent) {
        File dir = new File(parent.getValue().toString());
        File[] files = dir.listFiles();
        if (files != null) {
            for (File f : files) {
                PathNode child = new PathNode(f.getName(), f.getAbsolutePath(), f.isDirectory());
                parent.add(child);
            }
        }
        return parent;
    }

    public void initData(String rootPath) {
        File rootFile = new File(rootPath);
        PathNode root = new PathNode(rootFile.getName(), rootPath, rootFile.isDirectory());
        File[] files = rootFile.listFiles();
        if (files != null) {
            for (File f : files) {
                PathNode child = new PathNode(f.getName(), f.getAbsolutePath(), f.isDirectory());
                root.add(child);
            }
        }
        model = new DefaultTreeModel(root);
        tree.setModel(model);
        tree.setCellRenderer(new FileTreeRenderer());
    }

    // 內部類:節點模型
    static class PathNode extends DefaultMutableTreeNode {
        private Object value;
        private boolean isFolder;
        PathNode(String name, Object value, boolean isFolder) {
            super(name); this.value = value; this.isFolder = isFolder;
        }
        Object getValue() { return value; }
        boolean isFolder() { return isFolder; }
    }

    // 內部類:渲染器
    static class FileTreeRenderer implements TreeCellRenderer {
        private Icon folderOpen = new ImageIcon("icons/folder_open.jpg");
        private Icon folderClose = new ImageIcon("icons/folder_close.jpg");
        private Icon fileIcon = new ImageIcon("icons/file.gif");

        public Component getTreeCellRendererComponent(JTree tree, Object value,
                boolean sel, boolean expanded, boolean leaf, int row, boolean focus) {
            if (value instanceof PathNode) {
                PathNode n = (PathNode) value;
                JLabel label;
                if (n.isFolder()) {
                    label = new JLabel(n.getUserObject().toString(),
                            expanded ? folderOpen : folderClose, JLabel.RIGHT);
                } else {
                    label = new JLabel(n.getUserObject().toString(), fileIcon, JLabel.RIGHT);
                }
                return label;
            }
            return new JLabel();
        }
    }

    public static void main(String[] args) {
        new SystemFileTree().initData("D:/");
    }
}

進階優化建議

  • 載入期間將滑鼠游標設為 Cursor.WAIT_CURSOR,完成後恢復。
  • 大目錄可分頁或非同步載入(SwingWorker),避免阻塞 EDT。
  • 快取已讀取目錄,避免重複 I/O。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved