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

SWT/JFace 實戰:構建功能完整的文本瀏覽器應用

     編輯:Java 相關知識

前言

本文展示一個基於 ApplicationWindow 的完整文本瀏覽器範例,整合了選單列、工具列、狀態列、檔案開啟、非同步行數統計、圖示資源管理等 JFace 核心組件。代碼結構清晰,適合作為 RCP 風格桌面應用的起始模板。

架構概覽

  • ApplicationWindow:JFace 視窗基類,內建選單/工具/狀態列管理。
  • Action:命令模式封裝,綁定選單項、工具按鈕、快捷鍵。
  • IRunnableWithProgress:長時間任務的非同步執行與進度回報。
  • ImageDescriptor:延遲載入圖示資源。

核心代碼結構

1. 主視窗類

public class FileViewer extends ApplicationWindow {
    private Text text;                    // 核心編輯區
    private String content;               // 文字內容快取
    private String lineDelimiter;         // 換行符
    
    // 非同步行數統計任務
    private final IRunnableWithProgress runnableWithProgress = monitor -> {
        System.out.println("Running from thread: " + Thread.currentThread().getName());
        
        // UI 線程讀取文字內容
        getShell().getDisplay().syncExec(() -> {
            content = text.getText();
            lineDelimiter = text.getLineDelimiter();
        });
        
        monitor.beginTask("Counting total number of lines", content.length());
        int lines = 1;
        for (int i = 0; i < content.length(); i++) {
            if (monitor.isCanceled()) {
                monitor.done();
                System.out.println("Action cancelled");
                return;
            }
            if (i + lineDelimiter.length() < content.length()) {
                if (lineDelimiter.equals(content.substring(i, i + lineDelimiter.length()))) {
                    lines++;
                }
            }
            monitor.worked(1);
            try { Thread.sleep(1); } catch (InterruptedException ignored) {}
        }
        monitor.done();
        System.out.println("Total number of lines: " + lines);
    };

    // Action 定義
    private final Action actionCount = new Action("Count", 
        ImageDescriptor.createFromFile(null, "C:/icons/run.gif")) {
        public void run() {
            try {
                run(true, true, runnableWithProgress); // fork=true, cancelable=true
            } catch (InvocationTargetException | InterruptedException e) {
                e.printStackTrace();
            }
        }
    };

    private final Action actionOpenFile = new Action("Open",
        ImageDescriptor.createFromFile(null, "C:/icons/open.gif")) {
        public void run() {
            FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
            String file = dialog.open();
            if (file != null) {
                try {
                    String content = readFileAsAString(new File(file));
                    text.setText(content);
                    setStatus("File loaded successfully: " + file);
                } catch (IOException e) {
                    e.printStackTrace();
                    setStatus("Failed to load file: " + file);
                }
            }
        }
    };

    // 建構子
    public FileViewer(Shell parentShell) {
        super(parentShell);
        addMenuBar();
        addStatusLine();
        addToolBar(SWT.FLAT);
    }

    // 建立內容區
    @Override
    protected Control createContents(Composite parent) {
        getShell().setText("FileViewer v2.0");
        setStatus("Ready");
        
        text = new Text(parent, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
        text.setSize(300, 200);
        return text;
    }

    // 選單列構建
    @Override
    protected MenuManager createMenuManager() {
        MenuManager menuManager = new MenuManager("");
        
        MenuManager fileMenu = new MenuManager("&File");
        fileMenu.add(actionOpenFile);
        menuManager.add(fileMenu);
        
        MenuManager toolsMenu = new MenuManager("&Tools");
        toolsMenu.add(actionCount);
        menuManager.add(toolsMenu);
        
        return menuManager;
    }

    // 工具列構建
    @Override
    protected ToolBarManager createToolBarManager(int style) {
        ToolBarManager tbm = new ToolBarManager(style);
        tbm.add(actionOpenFile);
        tbm.add(actionCount);
        return tbm;
    }

    // 檔案讀取工具方法
    public static String readFileAsAString(File file) throws IOException {
        return new String(getBytesFromFile(file));
    }

    public static byte[] getBytesFromFile(File file) throws IOException {
        try (InputStream is = new FileInputStream(file)) {
            long length = file.length();
            if (length > Integer.MAX_VALUE) 
                throw new IllegalArgumentException("File too large (>2GB)");
            byte[] bytes = new byte[(int) length];
            int offset = 0, numRead;
            while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }
            if (offset < bytes.length) 
                throw new IOException("Could not completely read file: " + file.getName());
            return bytes;
        }
    }

    // 啟動入口
    public static void main(String[] args) {
        ApplicationWindow viewer = new FileViewer(null);
        viewer.setBlockOnOpen(true);
        viewer.open();
    }
}

關鍵技術點解析

1. ApplicationWindow 生命週期

// 1. 建構子:addMenuBar()/addToolBar()/addStatusLine()
// 2. createContents():建立中心內容區(必須覆寫)
// 3. createMenuManager()/createToolBarManager():構建選單/工具列(可選覆寫)
// 4. open():開啟視窗,進入事件循環
// 5. close():關閉視窗,釋放資源

2. Action 命令模式

  • 封裝:文字、圖示、快捷鍵、啟用狀態、執行邏輯。
  • 複用:同一 Action 可同時加入選單、工具列、右鍵選單。
  • 異步支援:run(true, true, IRunnableWithProgress) 自動顯示進度對話框。

3. 非同步進度任務

// IRunnableWithProgress.run(IProgressMonitor monitor)
// monitor.beginTask(taskName, totalWork)
// monitor.worked(workDone)
// monitor.isCanceled() 檢查用戶取消
// monitor.done() 結束
// 配合 Display.syncExec() 讀取 UI 組件狀態

4. 資源管理:ImageDescriptor

// 延遲載入,自動處理路徑、URL、流
ImageDescriptor.createFromFile(FileViewer.class, "icons/open.gif")
ImageDescriptor.createFromURL(url)
// 實際建立 Image 時才載入,避免啟動緩慢

5. 檔案讀取最佳實踐

  • 使用 try-with-resources 確保流關閉。
  • 檢查檔案大小防止 OOM(>2GB 拋異常)。
  • 分塊讀取應對大檔案(此處簡化為一次性讀取)。

擴展建議

  1. 編碼支援:檔案讀取時指定 Charset(UTF-8/Big5),或自動偵測 BOM。
  2. 大檔案分頁載入:使用 RandomAccessFile 或 MappedByteBuffer 實現虛擬滾動。
  3. 語法高亮:替換 Text 為 StyledText,結合 StyleRange 實現關鍵字著色。
  4. 搜尋/替換:新增 Find/Replace Action,使用 Text.findText()。
  5. 最近開啟檔案:用 PreferenceStore 持久化記錄。
  6. 拖放開啟:DropTarget 支援拖曳檔案到視窗開啟。

總結

此範例展示了 JFace ApplicationWindow 框架的標準用法:

  • 聲明式 UI 結構:Action、MenuManager、ToolBarManager 分離關注點。
  • 非阻塞長任務:IRunnableWithProgress + 進度監視器。
  • 資源抽象:ImageDescriptor 延遲載入圖示。
  • 標準對話框:FileDialog、訊息框等。

以此為基礎,可快速構建專業級 SWT/JFace 桌面應用。

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