打印及打印預(yù)覽是編寫應(yīng)用程序經(jīng)常要解決的問題,為了理解VC++對話框程序的打印及打印預(yù)覽實(shí)現(xiàn),要先掌握基于文檔/視圖的應(yīng)用程序打印及打印預(yù)覽的基本原理,。所以分為兩部分介紹,。 一、基于文檔/視圖的應(yīng)用程序的打印及打印預(yù)覽原理 VC++基于文檔/視圖的應(yīng)用程序中用MFC應(yīng)用程序向?qū)г诓襟E4對話框中選中Print and Print Preview選項(xiàng),,可以包含基本打印及打印預(yù)覽的支持,,應(yīng)用程序文件菜單中會(huì)生成兩個(gè)菜單項(xiàng)分別是打印(標(biāo)識(shí)符ID_FILE_PRINT)和打印預(yù)覽(標(biāo)識(shí)符:ID_FILE_PRINT_PREVIEW),,展開程序源代碼,,可以發(fā)現(xiàn),,是CVIEW類提供標(biāo)準(zhǔn)打印和打印預(yù)覽菜單命令的消息處理函數(shù): 設(shè)應(yīng)用程序視圖類為CMyView,展開MyView.cpp,其消息映象部分有如下兩行: ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView::OnFilePrintPreview) CView::OnFilePrint 和CView::OnFilePrintPreview函數(shù)都進(jìn)行打印操作,但View::OnFilePrint將實(shí)際發(fā)送到打印機(jī),,而CView::OnFilePrintPreview則將輸出發(fā)送到程序窗口上方顯示的預(yù)覽窗口顯示一個(gè)或兩個(gè)打印頁面的復(fù)制外觀,。利用上面加入的缺省打印支持,只能打印或預(yù)覽圖形的一個(gè)打印頁面,,一個(gè)頁中放不下的部分則放棄,,為了加強(qiáng)程序,使它打印整個(gè)圖形,,一頁中放不下的部分放在另一頁,,可以通過覆蓋幾個(gè)打印期間調(diào)用的虛擬函數(shù)來完成。下圖說明了整個(gè)打印和打印預(yù)覽的過程,,顯示了每個(gè)虛擬函數(shù)在程序中哪個(gè)部分調(diào)用,。注意每打印一個(gè)頁面就要經(jīng)歷圖中的一個(gè)循環(huán)。 下表列出了虛擬函數(shù)并介紹了各自完成的任務(wù),,由于MFC打印或打印預(yù)覽文檔時(shí)都調(diào)用虛擬函數(shù),,所以定義的覆蓋函數(shù)既影響打印也影響打印預(yù)覽。 二,、對話框程序打印及打印預(yù)覽的實(shí)現(xiàn) 以上是基于文檔/視圖的應(yīng)用程序的打印原理,,可以根據(jù)需要從CView類派生出視圖類覆蓋打印及打印預(yù)覽過程中的CView類的虛擬函數(shù)來定制文檔/視圖應(yīng)用程序的打印及打印預(yù)覽。在實(shí)際中,,有很多基于對話框的應(yīng)用程序,,也需要提供打印及打印預(yù)覽。但向?qū)]有給基于對話框應(yīng)用程序的基本支持,。有了以上知識(shí),,可以構(gòu)造出無文檔的視圖類,具體的實(shí)現(xiàn)時(shí),,增加三個(gè)類,,用以支持打印及打印預(yù)覽。以下用一具體實(shí)例說明,。 函數(shù)名[]覆蓋函數(shù)可能完成的任務(wù)CView::OnPreparePrinting[]調(diào)用CprintInfo成員函數(shù)(如CprintInfo::SetMaxPage設(shè)置文檔長度)或設(shè)置CprintInfo數(shù)據(jù)成員以影響Print對話框或打印預(yù)覽操作,,然后調(diào)用DoPreparePrinting生成用于打印或打印預(yù)覽的設(shè)備描述表(注意必須覆蓋OnPreparePrinting并調(diào)用DoPreparePrinting)CView::OnBeginPrinting[]分配專門用于打印的字體,畫筆,、畫刷和其它對象,,根據(jù)設(shè)備描述表計(jì)算并設(shè)置文檔長,在設(shè)備描述表上存放所需的消息(這是第一個(gè)訪問設(shè)備描述表的的虛擬函數(shù))CView::OnPrepareDC[]設(shè)置打印當(dāng)前頁面的文本或圖形屬性,,修改視圖原點(diǎn),,以打印當(dāng)前頁面,如果沒有設(shè)置文檔長度,,在文檔末尾終止打印循環(huán)(CprintInfo::m_bContinuePrinting賦值FALSE)CView::OnPrint[]調(diào)用OnDraw進(jìn)行輸出,;調(diào)用OnDraw前選擇OnBeginPrinting分配的字體,,調(diào)用OnDraw后取消對象,打印只出現(xiàn)在文檔打印版中的頁頭和頁腳,,如果打印輸出與屏幕輸出的外觀不同,, 在這里打印,而不是調(diào)用OnDrawCView::OnEndPrinting[]調(diào)用Cgdi::DeleteObject刪除OnBeginPrinting分配的對象1.用MFC應(yīng)用向?qū)?chuàng)建對話框應(yīng)用程序,,設(shè)主對話框類為CMyPrintPreviewDlg,在主對話框上放一按鈕,,(標(biāo)題:打印預(yù)覽,ID:IDC_BUTTON1),,用類向?qū)г黾悠銪N_CLICKED的消息響應(yīng)函數(shù)OnButton1生成打印預(yù)覽界面 void CMyPrintPreviewDlg::OnButton1() { CMyFrame* pf=new CMyFrame(this);// TODO: Add your control notification handler code here } 2,、增加新類: 用ClassWizard新建CMyFrame類(基類CFrameWnd),功能上相當(dāng)于文檔/視圖的應(yīng)用程序的框架窗口類 用ClassWizard新建CMyView類(基類CScrollView),功能上相當(dāng)于文檔/視圖的應(yīng)用程序的視圖類。 增加CMyPreviewView類(基類CPreviewView,注意在頭其定義頭文件中加入包含afxpriv.h),用于打印預(yù)覽界面的視圖類,。 3,、對新生成的各類修改如下: CMyFrame類: ①增加公有數(shù)據(jù)成員 CMyPrintPreviewDlg* m_pOldWnd:用于保存主對話框?qū)ο螅?/P> CMyView* m_pView:用于保存視圖類對象; ②重載構(gòu)造函數(shù),,保存對主對話框?qū)ο笾羔?,?chuàng)建窗口 CMyFrame::CMyFrame(CMyPrintPreviewDlg* pOld) { m_pOldWnd= pOld; if(!Create(NULL,“打印預(yù)覽”, WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,CRect(200,200,500,500))) TRACE0(“Failed to create view window\n”); } ③修改析構(gòu)函數(shù),讓主對話框顯示 CMyFrame::~CMyFrame() {m_pOldWnd->ShowWindow(SW_SHOW); } ④用ClassWizard增加WM_Create消息處理函數(shù),關(guān)聯(lián)CMyView視圖對象,;調(diào)用其OnFilePrintPreview函數(shù)進(jìn)行打印預(yù)覽(若要直接打印,,可直接向其發(fā)送消息);隱藏主對話框,。 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; CCreateContext context; context.m_pNewViewClass = RUNTIME_CLASS(CMyView); context.m_pCurrentFrame = this; context.m_pCurrentDoc = NULL; context.m_pLastView = NULL; m_pView = STATIC_DOWNCAST(CMyView, CreateView(&context)); if(m_pView != NULL) { m_pView->ShowWindow(SW_SHOW); SetActiveView(m_pView); } SetIcon(m_pOldWnd->GetIcon(FALSE),FALSE); SetIcon(m_pOldWnd->GetIcon(TRUE),TRUE); ShowWindow(SW_MAXIMIZE); CWinApp *pApp=AfxGetApp(),; pApp->m_pMainWnd=this; m_pView->OnFilePrintPreview(); //m_pView->SendMessage(WM_COMMAND, ID_FILE_PRINT);//直接打印 m_pOldWnd->ShowWindow(SW_HIDE); return 0; } 修改CMyView類 ①修改構(gòu)造函數(shù):將坐標(biāo)射模式置為缺省模式,。 CMyView::CMyView() { m_nMapMode = MM_TEXT; } ②增加消息映射實(shí)現(xiàn)打印,。 ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint) ③重載虛函數(shù)OnPreparePrinting,調(diào)用DoPreparePrinting生成用于打印或打印預(yù)覽的設(shè)備描述表,。 BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo) { return DoPreparePrinting(pInfo); } ④增加公有函數(shù)OnFilePrintPreview,,調(diào)用DoPrintPreview實(shí)現(xiàn)打印預(yù)覽,該函數(shù)需要傳入四個(gè)參數(shù):打印預(yù)覽工具條資源ID,,執(zhí)行打印及打印預(yù)覽的視圖對象指針,,打印預(yù)覽界面視圖類的 CRuntimeClass指針,打印預(yù)覽狀態(tài)類CPrintPreviewState對象指針,。 void CMyView::OnFilePrintPreview( ) { CPrintPreviewState* pState = new CPrintPreviewState; pState->lpfnCloseProc =_AfxMyPreviewCloseProc;//設(shè)置打印預(yù)覽窗口關(guān)閉時(shí)的調(diào)用函數(shù),; if(!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this,RUNTIME_CLASS(CMyPreviewView), pState)) { TRACE0(“Error: DoPrintPreview failed.\n”); AfxMessageBox(AFX_IDP_COMMAND_FAILURE); delete pState; } } ⑤在Myview.cpp文件中增加全局函數(shù),_AfxMyPreviewCloseProc,,當(dāng)單擊打印預(yù)覽窗口關(guān)閉按鈕時(shí)被調(diào)用,。 BOOL CALLBACK _AfxMyPreviewCloseProc(CFrameWnd* pFrameWnd) { ASSERT_VALID(pFrameWnd); CMyPreviewView* pView = (CMyPreviewView*) pFrameWnd->GetDlgItem(AFX_IDW_PANE_FIRST); ASSERT_KINDOF(CPreviewView, pView); pView->OnPreviewClose(); return FALSE; } 4、修改CMyPreviewView類,,增加工具欄按鈕的消息響應(yīng)函數(shù)OnPreviewClose(),,OnPreviewPrint(),,由于此類較簡單,列出該類代碼如下(注意粗體部分): MyPreviewView.h // MyPreviewView.h: interface for the CMyPreviewView class. // //////////////////////////////////////// #if !defined(AFX_MYPREVIEWVIEW_H__0AE8B670_B1AE_11DA_812E_00E04C39032F__INCLUDED_) #define AFX_MYPREVIEWVIEW_H__0AE8B670_B1AE_11DA_812E_00E04C39032F__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <afxpriv.h> class CMyPreviewView : public CPreviewView { DECLARE_DYNCREATE(CMyPreviewView) public: afx_msg void OnPreviewClose(); protected: CMyPreviewView(); virtual ~CMyPreviewView(); void OnDraw(CDC* pDC); void CMyPreviewView::OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView); afx_msg void OnPreviewPrint( ); DECLARE_MESSAGE_MAP( ) }; #endif // !defined(AFX_MYPREVIEWVIEW_H__0AE8B670_B1AE_11DA_812E_00E04C39032F__INCLUDED_) MyPreviewView.cpp // MyPreviewView.cpp: implementation of the CMyPreviewView class. #include “stdafx.h” #include “MyPrintPreviewDlg.h” #include “MyPreviewView.h” #include “MyFrame.h” #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////// IMPLEMENT_DYNCREATE(CMyPreviewView, CPreviewView) CMyPreviewView::CMyPreviewView() { } CMyPreviewView::~CMyPreviewView() { } BEGIN_MESSAGE_MAP(CMyPreviewView, CPreviewView) ON_COMMAND(AFX_ID_PREVIEW_CLOSE, OnPreviewClose) ON_COMMAND(AFX_ID_PREVIEW_PRINT, OnPreviewPrint) END_MESSAGE_MAP() void CMyPreviewView::OnDraw(CDC *pDC) { CPreviewView::OnDraw(pDC); m_pToolBar->PostMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE);// 控制條的命令狀態(tài)更新 } void CMyPreviewView::OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView) { CPreviewView::OnEndPrintPreview(pDC, pInfo, point, pView); } void CMyPreviewView::OnPreviewClose() { CMyFrame* pf=(CMyFrame*)::AfxGetMainWnd(); CWinApp *pApp=AfxGetApp(); pApp->m_pMainWnd=pf->m_pOldW; pf->DestroyWindow(); } void CMyPreviewView::OnPreviewPrint() { m_pPrintView->SendMessage(WM_COMMAND, ID_FILE_PRINT); } 至此,,基于對話框應(yīng)用程序的具有打印及打印預(yù)覽的基本支持已經(jīng)生成,,完全由新生成的三個(gè)類來支持。正如上一部分介紹的,,可以在CMyView類中定義CView類的幾個(gè)在打印過程中虛擬函數(shù)(CView::OnPreparePrinting,,CView::OnBeginPrinting,CView::OnPrepareDC,,CView::OnPrint,,CView::OnEndPrinting,具體內(nèi)容可參見前一部分)來定制其打印或打印預(yù)覽的內(nèi)容,。也可以將實(shí)現(xiàn)打印或打印預(yù)覽新增的三個(gè)類,,生成MFC擴(kuò)展動(dòng)態(tài)鏈接庫,以方便加入到程序中,。 |
|