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

C++Builder TPrinter 類詳解:打印機封裝、畫布繪圖、分頁控制與異常處理全攻略

     編輯:關於C++

C++Builder TPrinter 類詳解:打印機封裝、畫布繪圖、分頁控制與異常處理全攻略

TPrinter 封裝 Windows 打印子系統,提供設備無關畫布、分頁管理、多打印機選擇、打印作業生命週期控制的高層介面。全域單例 Printer()(定義於 Printers.hpp)即開箱即用。本文系統講解核心屬性、作業流程、畫布繪圖模式、常見陷阱與現代化列印架構建議。

類結構與單例訪問

TObject
  └── TPrinter  // 無繼承鏈,獨立封裝

// 全域訪問
#include <Printers.hpp>
TPrinter* Printer();  // 返回進程單例,內部引用計數管理

打印作業標準流程

void PrintDocument() {
    Printer()->BeginDoc();           // 1. 開啟作業,建立 DC
    try {
        // 繪製第 1 頁
        DrawPage(1);
        Printer()->NewPage();        // 2. 強制換頁,PageNumber++
        // 繼續繪製...
        DrawPage(2);
        Printer()->EndDoc();         // 3. 正常結束,提交列印佇列
    } catch (...) {
        Printer()->Abort();          // 4. 異常中止,丟棄作業
        throw;
    }
}

關鍵點:
- BeginDoc 後才能訪問 Canvas。
- EndDoc 才真正送入佇列;Abort 丟棄未列印數據。
- NewPage 重置 Canvas->PenPos = (0,0),PageNumber++。

核心屬性速查

屬性類型說明
CanvasTCanvas*當前頁畫布,支援所有繪圖方法
PageWidth/PageHeightint當前頁像素寬高(依 DPI、方向變化)
PageNumberint當前頁碼(1 基),NewPage 遞增
OrientationTPrinterOrientationpoPortrait/poLandscape,變更觸發 EndDoc
Copiesint份數,驅動程式支援時生效
PrinterIndexintPrinters 陣列索引,-1 為預設打印機
PrintersTStrings*系統安裝打印機名稱列表
FontsTStrings*當前打印機支援字體(含 TrueType 模擬)
TitleAnsiString列印管理器顯示的作業名稱
Abortedbool用戶/程式是否已中止
Printingbool作業是否進行中

畫布繪圖模式:座標系統與縮放

void DrawPage(int pageNo) {
    TCanvas* c = Printer()->Canvas;
    int pw = Printer()->PageWidth;
    int ph = Printer()->PageHeight;

    // 邏輯座標:建議以 0.1mm 為單位(或自定義)
    const double MM = 0.1;  // 1 单位 = 0.1mm
    int dpiX = GetDeviceCaps(c->Handle, LOGPIXELSX);
    int dpiY = GetDeviceCaps(c->Handle, LOGPIXELSY);
    double scaleX = dpiX / 2540.0;  // 2540 = 100 * 25.4 (0.1mm per inch)
    double scaleY = dpiY / 2540.0;

    c->Font->Size = 10;
    c->Font->Name = "微軟正黑體";
    c->TextOut(100 * scaleX, 50 * scaleY, "第 " + IntToStr(pageNo) + " 頁");

    // 繪製表格線
    c->Pen->Width = 1;
    c->MoveTo(50 * scaleX, 100 * scaleY);
    c->LineTo(500 * scaleX, 100 * scaleY);
}

關鍵:打印機 DC 採用裝置像素座標,無邏輯映射模式(MM_TEXT)。必須依 LOGPIXELSX/Y 自行換算物理單位。

多打印機與預設選擇

// 列舉
for (int i = 0; i < Printer()->Printers->Count; ++i)
    ListBox->Items->Add(Printer()->Printers->Strings[i]);

// 切換(會隱式 EndDoc 當前作業)
Printer()->PrinterIndex = desiredIndex;  // 或 SetPrinter(name, driver, port)

// 獲取預設打印機資訊
char dev[256], drv[256], port[256];
int mode;
Printer()->GetPrinter(dev, drv, port, mode);

異常處理與資源保護

  1. RAII 封裝:
    class ScopedPrintJob {
        bool started;
    public:
        ScopedPrintJob(const AnsiString& title) : started(false) {
            Printer()->Title = title;
            Printer()->BeginDoc();
            started = true;
        }
        ~ScopedPrintJob() {
            if (started) {
                if (Printer()->Aborted) Printer()->Abort();
                else Printer()->EndDoc();
            }
        }
        TCanvas* Canvas() { return Printer()->Canvas; }
    };
  2. 異常中:catch(...){ Printer()->Abort(); throw; } 確保不留殘留作業。
  3. 驅動程式崩潰:部分舊驅動在 EndDoc 死鎖,建議啟用 PrintToFile 測試或升級驅動。

常見陷阱

現象原因對策
輸出空白頁未呼叫 BeginDoc 直接繪圖嚴格遵循 BeginDoc → 繪圖 → EndDoc
字體模糊/缺字打印機不支援該字體,GDI 回退模擬僅使用 Printer()->Fonts 列表中的字體
分頁位置錯誤手動計算 Y 座標未考慮 PageHeight每次換頁檢查 PenPos.y > PageHeight - margin
雙面列印失效TPrinter 無雙面屬性需驅動程式 UI 設定或 DEVMODE 直接操作

現代化列印架構建議

對於複雜報表,建議棄用手繪 Canvas,改用:
① FastReport / ReportBuilder:VCL 原生報表引擎,支援數據綁定、分組、條碼、導出 PDF。
② HTML + wkhtmltopdf / Chromium Headless:以 Web 技術排版,轉 PDF 列印。
③ PDF 庫(PDFium, libharu):程式化生成 PDF,再 ShellExecute(print)。
TPrinter 仍是底層列印子系統的最終出口,掌握其畫布座標、作業生命週期與異常保護,是所有上層報表引擎穩定運作的基石。

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