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

SWT/JFace 列印功能實作指南:從基礎列印到文字編輯器列印支援

     編輯:Java 相關知識

SWT/JFace 列印功能概述

在 Eclipse SWT/JFace 應用程式中實作列印功能,核心在於 org.eclipse.swt.printing 套件。主要涉及 PrintDialog(列印對話框)、Printer(列印機抽象)、PrinterData(列印設定資料)以及 GC(繪圖上下文)的協同運作。本文將透過兩個完整範例,示範從簡單的文字列印到具備分頁、邊距計算的文字編輯器列印實作。

範例一:基礎文字列印 (SimplePrint)

此範例展示最精簡的列印流程:開啟列印對話框、啟動列印作業、繪製字串、結束分頁與作業。

核心步驟

  1. 建立 PrintDialog 並呼叫 open() 取得 PrinterData。
  2. 使用 PrinterData 實例化 Printer。
  3. 呼叫 printer.startJob() 開始作業,建立 GC 進行繪圖。
  4. 呼叫 printer.startPage() 開始分頁,使用 gc.drawString() 繪製內容。
  5. 依序呼叫 endPage()、endJob()、dispose() 釋放資源。

完整程式碼

package swt_jface.demo11;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class SimplePrint {
    Display display = new Display();
    Shell shell = new Shell(display);

    public SimplePrint() {
        shell.pack();
        shell.open();
        
        PrintDialog dialog = new PrintDialog(shell);
        PrinterData printerData = dialog.open();
        
        if (printerData != null) {
            Printer printer = new Printer(printerData);
            if (printer.startJob("Text")) {
                GC gc = new GC(printer);
                if (printer.startPage()) {
                    gc.drawString("Eclipse", 200, 200);
                    printer.endPage();
                }
                gc.dispose();
                printer.endJob();
            }
            printer.dispose();
            System.out.println("Print job done.");
        }

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
        display.dispose();
    }

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

範例二:文字編輯器列印支援 (Main)

此範例建立一個功能完整的文字編輯器,包含檔案開啟、字型/顏色設定,以及支援分頁、邊距、Tab 處理的進階列印功能。列印邏輯獨立執行於背景執行緒,避免阻塞 UI。

關鍵技術點

  • 分頁邏輯:在 printText() 中手動計算行高、字寬,處理換行符(\n, \r\n)與 Tab 鍵,超出右邊距或底邊距時自動換頁。
  • 資源管理:列印機專用的 Font、Color 必須在列印執行緒中建立並釋放。
  • 非同步列印:使用 Thread 執行 print() 方法,主 UI 執行緒保持響應。

完整程式碼

package swt_jface.demo11;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.jface.window.WindowManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.StyledTextPrintOptions;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.Printer;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.FontDialog;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class Main {
    ApplicationWindow applicationWindow;
    WindowManager manager;
    StyledTextPrintOptions styledTextPrintOptions;
    StyledText styledText;
    Display display;
    Shell shell;
    Text text;
    Font font;
    Color foregroundColor, backgroundColor;
    Printer printer;
    GC gc;
    Font printerFont;
    Color printerForegroundColor, printerBackgroundColor;
    int lineHeight = 0;
    int tabWidth = 0;
    int leftMargin, rightMargin, topMargin, bottomMargin;
    int x, y;
    int index, end;
    String textToPrint;
    String tabs;
    StringBuffer wordBuffer;

    public static void main(String[] args) {
        new Main().open();
    }

    void open() {
        display = new Display();
        font = new Font(display, "Courier", 10, SWT.NORMAL);
        foregroundColor = display.getSystemColor(SWT.COLOR_BLACK);
        backgroundColor = display.getSystemColor(SWT.COLOR_WHITE);
        shell = new Shell(display);
        shell.setLayout(new FillLayout());
        shell.setText("Print Text");
        shell.setMaximized(true);
        text = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
        text.setFont(font);
        text.setForeground(foregroundColor);
        text.setBackground(backgroundColor);

        // 建立選單列
        Menu menuBar = new Menu(shell, SWT.BAR);
        shell.setMenuBar(menuBar);
        MenuItem item = new MenuItem(menuBar, SWT.CASCADE);
        item.setText("&File");
        Menu fileMenu = new Menu(shell, SWT.DROP_DOWN);
        item.setMenu(fileMenu);

        // 開啟檔案
        item = new MenuItem(fileMenu, SWT.PUSH);
        item.setText("&Open...");
        item.setAccelerator(SWT.CTRL + 'O');
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) { menuOpen(); }
        });

        // 字型設定
        item = new MenuItem(fileMenu, SWT.PUSH);
        item.setText("Font...");
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) { menuFont(); }
        });

        // 前景色
        item = new MenuItem(fileMenu, SWT.PUSH);
        item.setText("Foreground Color...");
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) { menuForegroundColor(); }
        });

        // 背景色
        item = new MenuItem(fileMenu, SWT.PUSH);
        item.setText("Background Color...");
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) { menuBackgroundColor(); }
        });

        // 列印功能
        item = new MenuItem(fileMenu, SWT.PUSH);
        item.setText("&Print...");
        item.setAccelerator(SWT.CTRL + 'P');
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) { menuPrint(); }
        });

        new MenuItem(fileMenu, SWT.SEPARATOR);
        item = new MenuItem(fileMenu, SWT.PUSH);
        item.setText("E&xit");
        item.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent event) { System.exit(0); }
        });

        shell.pack();
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) display.sleep();
        }
        if (font != null) font.dispose();
        if (foregroundColor != null) foregroundColor.dispose();
        if (backgroundColor != null) backgroundColor.dispose();
    }

    void menuOpen() {
        FileDialog dialog = new FileDialog(shell, SWT.OPEN);
        dialog.setFilterExtensions(new String[] {"*.java", "*.*"});
        String name = dialog.open();
        if ((name == null) || (name.length() == 0)) return;

        try {
            File file = new File(name);
            FileInputStream stream = new FileInputStream(file.getPath());
            try {
                Reader in = new BufferedReader(new InputStreamReader(stream));
                char[] readBuffer = new char[2048];
                StringBuffer buffer = new StringBuffer((int) file.length());
                int n;
                while ((n = in.read(readBuffer)) > 0) {
                    buffer.append(readBuffer, 0, n);
                }
                text.setText(buffer.toString());
                stream.close();
            } catch (IOException e) {
                new MessageBox(shell, SWT.ICON_ERROR).setMessage("Error reading file:\n" + name).open();
            }
        } catch (FileNotFoundException e) {
            new MessageBox(shell, SWT.ICON_ERROR).setMessage("File not found:\n" + name).open();
        }
    }

    void menuFont() {
        FontDialog fontDialog = new FontDialog(shell);
        fontDialog.setFontList(font.getFontData());
        FontData fontData = fontDialog.open();
        if (fontData != null) {
            if (font != null) font.dispose();
            font = new Font(display, fontData);
            text.setFont(font);
        }
    }

    void menuForegroundColor() {
        ColorDialog colorDialog = new ColorDialog(shell);
        colorDialog.setRGB(foregroundColor.getRGB());
        RGB rgb = colorDialog.open();
        if (rgb != null) {
            if (foregroundColor != null) foregroundColor.dispose();
            foregroundColor = new Color(display, rgb);
            text.setForeground(foregroundColor);
        }
    }

    void menuBackgroundColor() {
        ColorDialog colorDialog = new ColorDialog(shell);
        colorDialog.setRGB(backgroundColor.getRGB());
        RGB rgb = colorDialog.open();
        if (rgb != null) {
            if (backgroundColor != null) backgroundColor.dispose();
            backgroundColor = new Color(display, rgb);
            text.setBackground(backgroundColor);
        }
    }

    void menuPrint() {
        PrintDialog dialog = new PrintDialog(shell, SWT.NULL);
        PrinterData data = dialog.open();
        if (data == null) return;
        if (data.printToFile) data.fileName = "print.out";

        textToPrint = text.getText();
        printer = new Printer(data);
        Thread printingThread = new Thread("Printing") {
            public void run() {
                print(printer);
                printer.dispose();
            }
        };
        printingThread.start();
    }

    void print(Printer printer) {
        if (printer.startJob("Text")) {
            Rectangle clientArea = printer.getClientArea();
            Rectangle trim = printer.computeTrim(0, 0, 0, 0);
            Point dpi = printer.getDPI();
            
            // 計算邊距 (含印表機不可列印區域)
            leftMargin = dpi.x + trim.x;
            rightMargin = clientArea.width - dpi.x + trim.x + trim.width;
            topMargin = dpi.y + trim.y;
            bottomMargin = clientArea.height - dpi.y + trim.y + trim.height;

            int tabSize = 4;
            StringBuffer tabBuffer = new StringBuffer(tabSize);
            for (int i = 0; i < tabSize; i++) tabBuffer.append(' ');
            tabs = tabBuffer.toString();

            gc = new GC(printer);

            // 建立列印機專用字型與顏色
            FontData fontData = font.getFontData()[0];
            printerFont = new Font(printer, fontData.getName(), fontData.getHeight(), fontData.getStyle());
            gc.setFont(printerFont);
            tabWidth = gc.stringExtent(tabs).x;
            lineHeight = gc.getFontMetrics().getHeight();

            RGB rgb = foregroundColor.getRGB();
            printerForegroundColor = new Color(printer, rgb);
            gc.setForeground(printerForegroundColor);

            rgb = backgroundColor.getRGB();
            printerBackgroundColor = new Color(printer, rgb);
            gc.setBackground(printerBackgroundColor);

            printText();
            
            printer.endJob();
            // 釋放列印機資源
            printerFont.dispose();
            printerForegroundColor.dispose();
            printerBackgroundColor.dispose();
            gc.dispose();
        }
    }

    void printText() {
        printer.startPage();
        wordBuffer = new StringBuffer();
        x = leftMargin;
        y = topMargin;
        index = 0;
        end = textToPrint.length();

        while (index < end) {
            char c = textToPrint.charAt(index);
            index++;
            if (c != 0) {
                if (c == 0x0a || c == 0x0d) { // 換行符
                    if (c == 0x0d && index < end && textToPrint.charAt(index) == 0x0a) index++; // 處理 \r\n
                    printWordBuffer();
                    newline();
                } else {
                    if (c != '\t') wordBuffer.append(c);
                    if (Character.isWhitespace(c)) {
                        printWordBuffer();
                        if (c == '\t') x += tabWidth;
                    }
                }
            }
        }
        if (y + lineHeight <= bottomMargin) printer.endPage();
    }

    void printWordBuffer() {
        if (wordBuffer.length() > 0) {
            String word = wordBuffer.toString();
            int wordWidth = gc.stringExtent(word).x;
            if (x + wordWidth > rightMargin) newline(); // 超出右邊距換行
            gc.drawString(word, x, y, false);
            x += wordWidth;
            wordBuffer = new StringBuffer();
        }
    }

    void newline() {
        x = leftMargin;
        y += lineHeight;
        if (y + lineHeight > bottomMargin) { // 超出底邊距換頁
            printer.endPage();
            if (index + 1 < end) {
                y = topMargin;
                printer.startPage();
            }
        }
    }
}

總結

SWT 列印機制雖然底層但靈活,開發者需自行處理分頁、換行、字型度量等排版邏輯。實際專案中,若需列印複雜報表或 StyledText 內容,可考慮使用 StyledTextPrintOptions 輔助,或引入 JasperReports、BIRT 等報表引擎以簡化開發。

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