共用方式為


TN030:自定義列印和列印預覽

備註

自第一次包含在在線文件中以來,尚未更新下列技術附注。 因此,某些程式和主題可能已過期或不正確。 如需最新信息,建議您搜尋在線檔索引中感興趣的主題。

此附註描述自訂列印和列印預覽過程,並說明在 CView 中使用的回呼例程和在 CPreviewView 的回呼例程及成員函式的用途。

問題

MFC 提供適用於大多數列印和列印預覽需求的完整解決方案。 在大部分情況下,只需少量額外的代碼即可使檢視具有列印和預覽的功能。 不過,有幾種方法可以優化列印,這些方法需要開發人員投入大量精力,而某些應用程式則需要在列印預覽模式中加入特定的使用者介面元素。

有效率的列印

當 MFC 應用程式使用標準方法列印時,Windows 會將所有圖形化裝置介面 (GDI) 輸出呼叫導向記憶體內部元檔。 當調用 EndPage 時,Windows 會針對印表機列印一頁所需的每個物理頻帶播放中繼檔案一次。 在此轉譯期間,GDI 經常會查詢中止程式,以判斷是否應該繼續。 通常中止程式允許處理訊息,讓使用者可以使用列印對話框中止列印作業。

不幸的是,這可能會減緩列印程式。 如果應用程式中的列印速度必須比使用標準技術時更快,您必須實作手動分段。

若要手動分帶列印,您必須重新實作列印迴圈,使OnPrint在每頁的各帶狀區塊中都多次呼叫(每個區塊呼叫一次)。 在 viewprnt.cpp 中,列印迴圈實作於 OnFilePrint 函式。 在 CView 衍生類別中,您會多載此函式,從而使專門處理列印命令的訊息對應項目可以呼叫您的 print 函式。 複製OnFilePrint程式並變更列印迴圈以實作分段列印。 您可能也會想要將分段矩形傳遞至列印功能,以便根據列印的頁面區段優化繪圖。

其次,在繪製帶狀時,您必須經常呼叫 QueryAbort 。 否則,不會呼叫中止程式,而且使用者將無法取消列印作業。

基本上,列印預覽會嘗試將顯示器轉換成印表機的模擬。 根據預設,主視窗的工作區是用來在視窗內完整顯示一或兩個頁面。 用戶可以放大頁面的區域,以更詳細地查看它。 有了額外的支援,使用者甚至可以在預覽模式中編輯檔。

自定義列印預覽

此附註只會處理修改列印預覽的一個方面:將UI新增至預覽模式。 可能進行其他修改,但這類變更已超過此討論的範圍。

將UI新增至預覽模式

  1. CPreviewView衍生檢視類別。

  2. 為您想要的 UI 層面新增命令處理程式。

  3. 如果您要將視覺層面新增至顯示,請覆寫OnDraw並在呼叫CPreviewView::OnDraw後執行繪圖。

檔案列印預覽

這是列印預覽的命令處理程式。 其預設實作為:

void CView::OnFilePrintPreview()
{
    // In derived classes, implement special window handling here
    // Be sure to Unhook Frame Window close if hooked.

    // must not create this on the frame. Must outlive this function
    CPrintPreviewState* pState = new CPrintPreviewState;

    if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,
        RUNTIME_CLASS(CPreviewView), pState))
    {
        // In derived classes, reverse special window handling
        // here for Preview failure case

        TRACE0("Error: DoPrintPreview failed");
        AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
        delete pState;  // preview failed to initialize, delete State now
    }
}

DoPrintPreview 將會隱藏應用程式的主要窗格。 控制列,例如狀態列,可以透過在 > 成員中指定來保留(這是一種位元遮罩,個別控制列的位元由 AFX_CONTROLBAR_MASK(AFX_IDW_MYBAR) 定義)。 窗戶 >pState-nIDMainPane 是會自動隱藏和重新顯示的窗戶。 DoPrintPreview 接著會建立標準預覽 UI 的按鈕列。 如果需要特殊窗口處理,例如隱藏或顯示其他視窗,應該在呼叫 DoPrintPreview 之前完成。

根據預設,當列印預覽完成時,它會將控制列傳回其原始狀態,並顯示主窗格。 如果需要特殊處理,應該在EndPrintPreview的覆寫中完成。 如果 DoPrintPreview 失敗,也提供特殊處理。

DoPrintPreview 被呼叫的參數是:

  • 預覽工具列之對話框範本的資源識別碼。

  • 負責執行列印預覽的檢視指標。

  • Preview View 類別的運行時間類別。 這會在 DoPrintPreview 中動態建立。

  • CPrintPreviewState 指標。 請注意,CPrintPreviewState 結構(如果應用程式需要保留更多狀態,則衍生結構) 不得 在畫面上建立。 DoPrintPreview 是非模態的,而且此結構必須保持,直到呼叫 EndPrintPreview 為止。

    備註

    如果列印支援需要個別的檢視或檢視類別,該物件的指標應該傳遞為第二個參數。

結束列印預覽

這是用來終止列印預覽模式。 在大多數情況下,移動到文件中上次於列印預覽中顯示的頁面是可取的。 EndPrintPreview 是應用程式執行此動作的機會。 pInfo->m_nCurPage 成員是上次顯示的頁面(如果顯示兩個頁面,則為最左邊的頁面),而指標是用於提示使用者在頁面上感興趣的位置。 由於架構中應用程式檢視的結構未知,因此您必須提供程式代碼以移至所選的點。

您應該先執行大部分的動作,再呼叫 CView::EndPrintPreview。 此呼叫會逆轉 DoPrintPreview 的效果,並刪除 pView、pDC 和 pInfo。

// Any further cleanup should be done here.
CView::EndPrintPreview(pDC, pInfo, point, pView);

CWinApp::OnFilePrintSetup

這必須對應到 [列印設定] 功能表項。 在大部分情況下,不需要覆蓋執行。

頁面命名法

另一個問題是頁碼和順序。 對於簡單的字處理器類型應用程式,這是一個直接的問題。 大部分的列印預覽系統都假設每個列印的頁面都對應至檔中的一頁。

嘗試提供一般化解決方案時,需要考慮數件事。 想像一下 CAD 系統。 用戶的繪圖覆蓋數張 E 大小紙張。 在 E 大小(或較小、縮放的)繪圖機上,頁碼會如同簡單情況一樣。 但是在雷射印表機上,每張紙列印 16 個 A 大小頁面,列印預覽會將什麼視為「頁面」?

如介紹段落所述,列印預覽會像印表機一樣。 因此,使用者會看到會從選取的特定印表機中取出的內容。 由視圖決定每個頁面上所列印的影像。

結構中的 CPrintInfo 頁面描述字串會提供一種方法,來向用戶顯示頁碼,如果每個頁面可以用一個數字表示的話(如「第 1 頁」或「第 1-2 頁」所示)。 默認的 實作 CPreviewView::OnDisplayPageNumber會使用此字串。 如果需要不同的顯示,可以覆蓋此虛擬函式以提供,例如“Sheet1、Sections A、B”。

另請參閱

依編號的技術注意事項
依類別排序的技術注意事項