1. 程式人生 > >VC++對話方塊程式列印及列印預覽的實現(三)

VC++對話方塊程式列印及列印預覽的實現(三)

本文首先介紹了利用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,實現在對話方塊中的列印和列印預覽功能,極大的簡化了對話方塊列印程式的編寫。