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

VC++ 對話框客戶區內容列印完整實作

     編輯:關於VC++

需求背景

基於對話框的應用程式(無標題列、功能表),需在客戶區繪圖並支援列印。MFC 文檔/視圖架構自帶列印支援,但對話框專案需自行實作:建立印表機 DC、處理列印對話框、將客戶區內容轉印至列印 DC。

核心挑戰與解決方案

問題解決策略
無功能表,如何觸發列印註冊熱鍵 Ctrl+P (RegisterHotKey) 呼叫列印流程
不知印表機名稱,無法 CreateDC使用 CPrintDialog 讓使用者選擇印表機,取得 DEVMODE/DEVNAMES 建立 DC
直接 BitBlt 客戶區到印表機 DC中介步驟:客戶區 → 記憶體 DC → 列印 DC,解決縮放與覆蓋問題
列印對話框遮蓋客戶區,導致 BitBlt 到黑框關鍵技巧:在 OnPaint 中持續將客戶區內容備份至成員變數 CBitmap m_bmpMem;列印時直接使用此備份位圖
無標題列對話框拖移處理 WM_NCHITTEST 回傳 HTCAPTION 實現任意處拖移

關鍵程式碼架構

成員變數宣告

class CPrintDlg : public CDialog
{
    CBitmap m_bmpMem;      // 客戶區內容備份
    CDC     m_dcMem;       // 對應記憶體 DC
    BOOL    m_bMemReady;   // 備份是否就緒
    // ...
};

OnPaint:繪圖並同步備份

void CPrintDlg::OnPaint()
{
    CPaintDC dc(this);
    CRect rect; GetClientRect(&rect);

    // 1. 建立/調整記憶體 DC 與位圖
    if (!m_bMemReady || m_bmpMem.GetWidth() != rect.Width() || m_bmpMem.GetHeight() != rect.Height()) {
        if (m_bMemReady) { m_bmpMem.DeleteObject(); m_dcMem.DeleteDC(); }
        m_dcMem.CreateCompatibleDC(&dc);
        m_bmpMem.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());
        m_dcMem.SelectObject(&m_bmpMem);
        m_bMemReady = TRUE;
    }

    // 2. 在記憶體 DC 上繪製實際內容(此處替換為你的繪圖邏輯)
    CBrush brush(RGB(255,255,255)); // 白底
    m_dcMem.FillRect(&rect, &brush);
    // ... 你的繪圖代碼:m_dcMem.Ellipse(...), m_dcMem.TextOut(...) 等 ...

    // 3. 將記憶體 DC 複製到螢幕(雙緩衝,無閃爍)
    dc.BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcMem, 0, 0, SRCCOPY);
}

列印流程 OnPrint

void CPrintDlg::OnPrint()
{
    if (!m_bMemReady) return;

    CPrintDialog dlg(FALSE); // FALSE = 列印對話框
    if (dlg.DoModal() != IDOK) return;

    // 1. 取得印表機 DC
    HDC hPrinterDC = dlg.GetPrinterDC(); // MFC 封裝
    if (!hPrinterDC) return;
    CDC dcPrinter; dcPrinter.Attach(hPrinterDC);

    // 2. 開始列印文件
    DOCINFO di = { sizeof(DOCINFO), _T("對話框列印輸出") };
    dcPrinter.StartDoc(&di);
    dcPrinter.StartPage();

    // 3. 計算縮放比例(保持長寬比置中)
    CRect rectClient; GetClientRect(&rectClient);
    int nPageW = dcPrinter.GetDeviceCaps(HORZRES);
    int nPageH = dcPrinter.GetDeviceCaps(VERTRES);
    double scale = min((double)nPageW / rectClient.Width(), (double)nPageH / rectClient.Height());
    int drawW = (int)(rectClient.Width() * scale);
    int drawH = (int)(rectClient.Height() * scale);
    int x = (nPageW - drawW) / 2;
    int y = (nPageH - drawH) / 2;

    // 4. 直接使用備份位圖輸出(不受列印對話框遮蓋影響)
    dcPrinter.StretchBlt(x, y, drawW, drawH, &m_dcMem, 0, 0, rectClient.Width(), rectClient.Height(), SRCCOPY);

    dcPrinter.EndPage();
    dcPrinter.EndDoc();
    dcPrinter.Detach(); // 釋放 DC 所有權,避免 MFC 釋放時出錯
}

熱鍵註冊與訊息處理

BOOL CPrintDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    RegisterHotKey(m_hWnd, 1, MOD_CONTROL, 'P'); // ID=1
    return TRUE;
}

void CPrintDlg::OnDestroy()
{
    UnregisterHotKey(m_hWnd, 1);
    CDialog::OnDestroy();
}

LRESULT CPrintDlg::OnHotKey(WPARAM wParam, LPARAM lParam)
{
    if (wParam == 1) OnPrint();
    return 0;
}
// 需在訊息對映表加入 ON_MESSAGE(WM_HOTKEY, OnHotKey)

原始碼下載

完整專案(VC6 / XP 測試通過):
https://www.vckbase.com/code/downcode.asp?id=2313

總結

對話框列印的核心在於**記憶體 DC 持久化備份客戶區內容**,配合 CPrintDialog 取得印表機 DC,最後用 StretchBlt 處理縮放。此模式同樣適用於無 MFC 文檔/視圖支援的任何視窗列印需求。

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