一次性構建整棵檔案樹的 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,完成後恢復。