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

JavaFX 實現「我的電腦」資源管理器:TreeView + TableView 文件系統瀏覽

     編輯:Java 相關知識

項目目標

使用 JavaFX 構建一個輕量級文件資源管理器,左側 TreeView 顯示目錄樹結構,右側 TableView 顯示當前目錄下文件詳情 (名稱、類型、修改時間、大小)。採用惰性加載優化大目錄性能。

架構設計

  • FileTreeItem:繼承 TreeItem<File>,重寫 getChildren() 與 isLeaf() 實現按需掃描子目錄。
  • FileDetail:文件信息展示模型,封裝名稱、類型、大小、修改時間,支援 TableView 列綁定。
  • 主應用類:構建 UI、綁定選中事件、雙向數據流。

核心代碼實現

1. 文件詳情模型


package com.example.filemanager;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class FileDetail {
    private final String fileName;
    private final String type;
    private final String lastModified;
    private final long length;
    private final boolean isDirectory;

    public FileDetail(File file) {
        this.fileName = file.getName();
        this.isDirectory = file.isDirectory();
        
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        this.lastModified = fmt.format(new Date(file.lastModified()));
        
        if (isDirectory) {
            this.type = "文件夾";
            this.length = 0;
        } else {
            this.length = file.length();
            this.type = String.format("%.1f KB", length / 1024.0);
        }
    }

    // Getter 方法 (PropertyValueFactory 需要)
    public String getFileName() { return fileName; }
    public String getType() { return type; }
    public String getLastModified() { return lastModified; }
    public long getLength() { return length; }
    public boolean isDirectory() { return isDirectory; }
}

2. 惰性加載樹節點


package com.example.filemanager;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.TreeItem;
import java.io.File;

public class FileTreeItem extends TreeItem {
    private boolean isFirstTimeChildren = true;
    private boolean isFirstTimeLeaf = true;

    public FileTreeItem(File file) {
        super(file);
        // 設置圖標 (可選)
        // setGraphic(new ImageView(isDirectory ? folderIcon : fileIcon));
    }

    @Override
    public ObservableList> getChildren() {
        if (isFirstTimeChildren) {
            isFirstTimeChildren = false;
            super.getChildren().setAll(buildChildren(this));
        }
        return super.getChildren();
    }

    @Override
    public boolean isLeaf() {
        if (isFirstTimeLeaf) {
            isFirstTimeLeaf = false;
            File f = getValue();
            isLeaf = f.isFile(); // 文件是葉子節點,目錄不是
        }
        return isLeaf;
    }

    private ObservableList> buildChildren(TreeItem item) {
        File dir = item.getValue();
        if (dir != null && dir.isDirectory()) {
            File[] files = dir.listFiles();
            if (files != null) {
                ObservableList> children = FXCollections.observableArrayList();
                for (File child : files) {
                    // 可選: 過濾隱藏文件、系統文件
                    if (!child.isHidden()) {
                        children.add(new FileTreeItem(child));
                    }
                }
                return children;
            }
        }
        return FXCollections.emptyObservableList();
    }
}

3. 主應用與 UI 綁定


package com.example.filemanager;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import java.io.File;

public class FileManagerApp extends Application {

    private final ObservableList tableData = FXCollections.observableArrayList();

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("JavaFX 文件資源管理器");

        // 根節點: 計算機名稱
        String computerName = System.getenv("COMPUTERNAME") != null ? 
                              System.getenv("COMPUTERNAME") : "This PC";
        TreeItem rootItem = new TreeItem<>(new File(computerName));
        
        // 添加所有根目錄 (Windows: C:\, D:\... ; Linux: /)
        for (File root : File.listRoots()) {
            rootItem.getChildren().add(new FileTreeItem(root));
        }
        rootItem.setExpanded(true); // 默認展開根節點

        // TreeView
        TreeView treeView = new TreeView<>(rootItem);
        treeView.setShowRoot(true);
        treeView.setPrefWidth(300);

        // TableView
        TableView tableView = new TableView<>(tableData);
        tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        TableColumn colName = new TableColumn<>("名稱");
        colName.setCellValueFactory(new PropertyValueFactory<>("fileName"));
        colName.setPrefWidth(200);

        TableColumn colType = new TableColumn<>("類型");
        colType.setCellValueFactory(new PropertyValueFactory<>("type"));
        colType.setPrefWidth(100);

        TableColumn colModified = new TableColumn<>("修改時間");
        colModified.setCellValueFactory(new PropertyValueFactory<>("lastModified"));
        colModified.setPrefWidth(180);

        TableColumn colSize = new TableColumn<>("大小");
        colSize.setCellValueFactory(new PropertyValueFactory<>("length"));
        colSize.setPrefWidth(100);

        tableView.getColumns().addAll(colName, colType, colModified, colSize);

        // 選中事件: 更新右側表格
        treeView.getSelectionModel().selectedItemProperty()
            .addListener((obs, oldSel, newSel) -> {
                if (newSel != null) {
                    ObservableList> kids = newSel.getChildren();
                    ObservableList details = FXCollections.observableArrayList();
                    for (TreeItem kid : kids) {
                        details.add(new FileDetail(kid.getValue()));
                    }
                    tableData.setAll(details);
                }
            });

        // 布局: HBox 雙欄自適應
        HBox root = new HBox();
        HBox.setHgrow(treeView, Priority.ALWAYS);
        HBox.setHgrow(tableView, Priority.ALWAYS);
        root.getChildren().addAll(treeView, tableView);

        Scene scene = new Scene(root, 900, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

關鍵技術點解析

技術點說明
TreeItem 惰性加載重寫 getChildren() 與 isLeaf(),僅在展開節點時掃描磁盤,避免啟動時遞歸掃描全盤導致卡頓
PropertyValueFactory依據 JavaBean 命名慣例 (getXxx) 自動綁定表格列,要求模型類有公共 Getter
ObservableListFXCollections 可觀察列表,自動通知 UI 更新,無需手動刷新
ChangeListener監聽 TreeView 選中項變化,觸發右側數據重載
HBox + Priority.ALWAYS雙欄自適應寬度,拖動窗口時左右面板同步縮放

進階優化方向

  • 異步掃描:Task<ObservableList> 後台線程掃描大目錄,完成後 Platform.runLater 更新 UI,防止界面凍結。
  • 圖標支援:使用 FileSystemView.getFileSystemView().getSystemIcon(file) 獲取系統原生圖標 (需 Swing 互操作) 或第三方圖標庫 (如 FontAwesomeFX)。
  • 文件過濾/搜索:添加文本框過濾 TableView 數據 (用 FilteredList 包裝)。
  • 右鍵菜單:複製、粘貼、刪除、重命名、屬性 (調用 java.nio.file.Files API)。
  • 虛擬化大數據:TableView 內建虛擬化,但極大目錄 (10萬+) 仍建議分頁或虛擬滾動加載。

運行效果

JavaFX 文件管理器運行截圖 左側目錄樹,右側文件詳情表格,支援多級展開、欄位排序、自適應佈局

總結

JavaFX 的 TreeView + TableView + ObservableList 組合極適合構建文件瀏覽類應用。核心在於 FileTreeItem 惰性加載 解決性能問題,PropertyValueFactory 簡化數據綁定。該架構易於擴展為功能完整的資源管理器,也是學習 JavaFX MVC 模式、屬性綁定、集合觀察的優秀實戰項目。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved