摘要
本文首先介紹了利用MFC提供的文檔視圖框架來實現一個打印程序,實現打印預覽,在此基礎上,同時通過對MFC源代碼的深入探討,提出了利用該方法在對話框上用MFC實現打印功能,結果表明,利用MFC實現打印不僅方便,而且功能很強大,能夠根據不同的需求很方便的打印出所需要的格式。本文還實現了一個在對話框中利用MFC實現打印功能的一個框架結構,對於使用者只要使用該結構就可以按照自己的要求打印任何內容。
關鍵詞:Visual C++ ,MFC,對話框, 打印 ,打印預覽
引言
打印程序的編寫在windows程序設計中非常有用,針對不同的用戶需要,通常用sdk方式實現打印代碼量比較大,而且要對打印流程的底層有非常清楚的了解,需要一個程序員有非常深入的打印方面的知識,利用MFC提供的文檔視圖結構,不但可以實現一些常用的標准界面元素,把數據的處理的界面的處理分離出來,而且其提供的打印功能更是方便快捷,功能強大。打印程序的編寫本質是是一種GDI繪圖,只是繪圖的對象是在打印機的設備描述表,如果對於屏幕的GDI繪圖比較熟悉的讀者,相信掌握打印程序的編寫應該比較容易。
1、文檔視圖結構的程序的打印程序的編寫
通常情況下,一個結構組織的比較好的MFC程序是基於文檔視圖結構的,這一框架結構給我們提供了很多功能,比如菜單,注冊表的關聯,文件類型的注冊,打印功能,只要我們善於發掘,這些都可以為我們所用,但我們現在只關心如何使用MFC提供的結構來實現打印功能。
在編寫打印程序之前,有必要先介紹一下MFC的框架結構,其中的文檔視圖結構又是這個框架的重點,我們通過分析MFC實現的視圖類的原代碼就可以看到一個打印程序的執行流程。讀者也可以看侯俊傑的《深入淺出MFC》,上面有關於MFC打印的詳細流程解釋,下面是MFC的打印的函數的實現,該函數名為OnFilePrint它不是一個虛函數,而是響應缺省的COMMAND消息的處理函數,因為MFC提供了向導生成的菜單和工具欄,關於打印的命令ID為ID_FILE_PRINT ,而在視圖類的MessageMap裡有這樣一項,ON_COMMAND (ID_FILE_PRINT, CView::OnFilePrint),因此實際使用的過程中可以不用原來的ID, 而使用自己的ID如ID_MYPRINT,再在MessageMap裡加入ON_COMMAND (ID_MYPRINT, CView::OnFilePrint)即可完成原來一樣的功能。ViewPrnt.cpp中有CView的OnFilePrint的函數的具體實現,ViewPrnt.cpp的位置讀者自己用windows查找就能找到,這是MFC的源代碼,本文把其中的主要代碼列出放在下面,直接看下面的分析:
void CView::OnFilePrint()
{
// get default print info
if (OnPreparePrinting(&printInfo))
{
if (dlg.DoModal() != IDOK)
return;
}
OnBeginPrinting(&dcPrint, &printInfo);
OnPrepareDC(&dcPrint, &printInfo);
OnPrint(&dcPrint, &printInfo);
OnEndPrinting(&dcPrint, &printInfo); // clean up after printing
}
其中加粗的代碼行為可以重載的虛函數,根據不同的用戶,其內容會不同。對於 OnPreparePrinting() 函數的具體內容必須有 return DoPreparePrinting(pInfo);這是在一個打印過程中最先調用的。當然也可以包含一些其它的打印初始化操作。我們最主要的是要重載三個函數:
OnBeginPrinting();
OnPrint();
OnEndPrinting();
而以 OnPrint 最為復雜,它是我們要寫大量代碼實現我們打印功能的地方。對於默認的OnPrint實現是調用CView的OnDraw,也就是和繪制視圖類的客戶區的內容完全相同的方法來在打印機上繪圖。實際中我們在兩種地方繪圖的內容是完全不同的,可能用戶在客戶區繪的是一個曲線,而在打印機上要繪制表格和數據。OnPrint(CDC* pDC, CPrintInfo* pInfo)的第二個參數是一個CPrintInfo類型的指針,我們可以從這個指針指向的對象中獲得很多信息,如總共的頁數,當前的頁數,這在打印頁眉頁腳時可能是很有用的信息。CPrintInfo的定義如下:
struct structCPrintInfo // Printing information structure
{
CPrintInfo();
~CPrintInfo();
CPrintDialog* m_pPD; // pointer to print dialog
BOOL m_bDocObject; // TRUE if printing by IPrint interface
BOOL m_bPreview; // TRUE if in preview mode
BOOL m_bDirect; // TRUE if bypassing Print Dialog
BOOL m_bContinuePrinting;// set to FALSE to prematurely end printing
UINT m_nCurPage; // Current page
UINT m_nNumPreviewPages; // Desired number of preview pages
CString m_strPageDesc; // Format string for page number display
LPVOID m_lpUserData; // pointer to user created struct
CRect m_rectDraw; // rectangle defining current usable page area
// these only valid if m_bDocObject
UINT m_nOffsetPage; // offset of first page in combined IPrint job
DWORD m_dwFlags; // flags passed to IPrint::Print
void SetMinPage(UINT nMinPage);
void SetMaxPage(UINT nMaxPage);
UINT GetMinPage() const;
UINT GetMaxPage() const;
UINT GetFromPage() const;
UINT GetToPage() const;
UINT GetOffsetPage() const;
};
OnBeginPrinting()通常用來設定要打印的總頁數,以及一些和頁面尺寸有關的初始化工作,在OnBeginPrinting()中設定打印的頁數是必要的,默認的頁數是只有一頁,如果開發人員打印的頁數大於1,則必須在此函數中設定打印的頁數。然後在OnPrint(CDC* pDC, CPrintInfo* pInfo)中用pInfo-> m_nCurPage獲取當前的頁碼,根據當前的頁碼打印該頁相應的內容。OnEndPrinting用來釋放在OnBeginPrinting中申請的資源,如果沒有申請,則不需重載該函數。
關於打印預覽只需要將自己的執行打印預覽功能的命令ID和CView::OnFilePrintPreview關聯起來就行了,具體方法是在用戶的視圖類的MessageMap中加入:
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview);
其中ID_FILE_PRINT_PREVIEW是默認的ID,開發人員也可以使用自己的ID。其實只要重載了OnPrint函數,在打印和打印預覽中就可以重用該函數了。到現在為止,相信讀者已經對利用MFC的文檔視圖結構來實現一個包含打印和打印預覽功能的程序有了一個總體的認識了,本文還針對該方法給出了一個示例代碼,代碼來自Jeff Prosise 的《MFC windows程序設計》,見參考文獻[1]。
2、沒有文檔視圖結構的程序中利用MFC進行打印程序的編寫
如果程序不是文檔視圖結構的,我們要使用MFC來進行打印,則可以通過建立一個虛擬的文檔視圖結構來進行打印,其實MFC的打印的強大功能是在CView裡提供的,而CView類的對象是一個子窗口,它必須是某一個框架窗口的子窗口,而在對話框程序中,我們只需要打印,而不需要顯示這個框架窗口和視圖。我們以按下按鈕"打印"來執行打印程序,例如按鈕為ID為IDC_PNT,消息相應函數為OnPnt(),即:
ON_BN_CLICKED(IDC_PNT, OnPnt);
需要在OnPnt中建立一個框架窗口,同時使某個CView類的對象為該窗口的子窗口。因此筆者建立了兩個類,一個為框架窗口類CPrintFrame,另一個為CPrintView,具體的內容見示例代碼。在新建一個用於打印的虛擬框架窗口時,需要將執行打印的對話框的指針傳給框架窗口,這以便在對話框來響應WM_BEGIN_PRINTING和WM_END_PRINTING消息,使對話框可以完成打印的初始化和釋放操作。在執行一個打印任務時,將打印的流程交給CView來進行,而這個CView是虛擬的,只是用來完成打印一些操作,其它內容則完全不負責處理,而當要執行CView::OnPrint時,則又將處理的具體內容傳回到對話框,而對話框則只需要響應WM_MY_PRINT消息即可:
pFrame->m_pCallerDlg->SendMessage(WM_MY_PRINT,(WPARAM) pDC, (LPARAM) pInfo);
使打印的具體處理又傳回到對話框中,使開發人員根據具體的需要寫WM_MY_PRINT的處理函數就可以實現打印,而CView::OnPrint(CDC* pDC, CPrintInfo* pInfo)的參數也從WM_MY_PRINT的消息參數傳出來,在用戶的對話框程序中,需要寫的代碼就很少,主要有以下幾個步驟,
建立一個CPrintFrame的對象,設該對象的指針為pFrame,並將對話框的指針傳給該對象的m_pCallerDlg,即pFrame->m_pCallerDlg = this;
調用對象的Create函數創建框架窗口;例如pFrame->Create(NULL,"頻譜打印",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));
如果要執行打印,則調用pFrame->m_pView->OnMyPrint();
如果要執行打印預覽,則調用:
pFrame->m_pView->OnMyPrintPreview();例如:
void CDlgPrintDlg::OnPrint() //執行打印功能
}
{
CPrintFrame *pFrame = new CPrintFrame;
pFrame->m_pCallerDlg = this;
pFrame->Create(NULL,"Curve
Print",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));
pFrame->m_pView->OnMyPrint();
}
void CDlgPrintDlg::OnPrintPreview() //執行打印預覽功能
{
CPrintFrame *pFrame = new CPrintFrame;
pFrame->m_pCallerDlg = this;
pFrame->Create(NULL,"Curve Print
Preview",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));
pFrame->m_pView->OnMyPrintPreview();
在對話框中響應 WM_BEGIN_PRINTING, WM_END_PRINTING,WM_MY_PRINT消息,分別完成打印的初始化,釋放和具體的打印操作;
如在示例程序中添加了三個消息響應函數來執行該功能。
ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting)
ON_MESSAGE(WM_END_PRINTING,OnEndPrinting)
ON_MESSAGE(WM_MY_PRINT,OnMyPrint)
其中OnMyPrint是跟具體要打印什麼內容有關的開發人員要重點完成的代碼,可以打印表格,圖片,數據,只要GDI繪圖可以進行的操作在這裡都可以完成。由於打印預覽的一部分工作在CView類裡完成,因此在用戶程序中只需要相應WM_MY_PRINT消息就可以執行打印預覽的功能,而不需要另外編寫打印預覽代碼。
本文提供的CPrintFrame和CPrintView類是連個可重用的類,開發者只需要把這兩個類對應的四個文件拷貝到工程文件所在目錄中(PrintFrame.h, PringtView.h,PrintFrame.cpp, PrintView.cpp),並將這四個文件加入工程,並在需要執行打印功能的代碼處加入
#include "PrintFrame.h"
#include "PrintView.h"
然後按照上述5個步驟進行即可以實現一個功能完整的打印程序,利用上述類實現對話框打印不但節省開發者許多時間,而且功能很強大,能達到很專業的水平,但是該方法有一個缺點,筆者發現如果開發者使用靜態連接的MFC庫時則會出錯,只適用於Use MFC in a Shelled DLL情況,而且必須使程序為Debug版本的。3、示例代碼的執行效果
圖1 執行打印功能的對話框
當按下打印預覽後則會產生一個框架窗口,顯示打印預覽的內容,如圖2所示:
圖2 打印預覽效果圖
可以在上圖的界面上按兩頁同時對兩頁預覽,如圖3所示:
圖3 兩頁同時預覽效果圖
但有一點需要注意,在預覽界面上的打印按鈕不可用,如果按該"打印"鈕則直接等於將預覽窗口關掉,因此要執行打印功能必須另外在對話框的界面上放一個打印按鈕,如果執行了"打印"功能,則會彈出一個選擇打印機的對話框,如圖4所示。這個對話框是MFC的打印結構內置的,不可以消除,當用戶選擇了正確的打印機後則可以打印出具體的內容了。
圖4 打印機選擇對話框
4、 結束語
本文從分析MFC的原代碼入手,利用MFC的CView類提供的打印和打印預覽功能進行了在對話框中的打印和打印預覽。利用面向對象的C++寫了兩個可重用類CPrintFrame和CPrintView,實現在對話框中的打印和打印預覽功能,極大的簡化了對話框打印程序的編寫。
參考文獻
[1]Jeff Prosise,Programming Windows with MFC - 2nd ed,Microsoft Press,1999.
[2]Charles Petzold, Programming Windows-5th ed,Microsoft Press,1998.
[3]侯俊傑,深入淺出MFC,華中科技大學出版社,1999
本文配套源碼