VC++對話方塊程式列印及列印預覽的實現(一)
張明奇(卡哥)註釋:成功版本
MFC文件/檢視的應用程式,嚮導給了列印及列印預覽的標準支援。使這類應用程式列印及列印預覽工作得以簡化。另一類對話方塊程式卻沒有相應支援,從MFC列印及列印預覽的標準支援入手,可以在對話方塊程式中,增加三個類以支援列印及列印預覽,本文介紹了這三個類的實現。
列印及列印預覽是編寫應用程式經常要解決的問題,為了理解VC++對話方塊程式的列印及列印預覽實現,要先掌握基於文件/檢視的應用程式列印及列印預覽的基本原理。所以分為兩部分介紹。
一、基於文件/檢視的應用程式的列印及列印預覽原理
VC++基於文件/檢視的應用程式中用MFC應用程式嚮導在步驟4對話方塊中選中Print and Print Preview選項,可以包含基本列印及列印預覽的支援,應用程式檔案選單中會生成兩個選單項分別是列印(識別符號ID_FILE_PRINT)和列印預覽(識別符號:ID_FILE_PRINT_PREVIEW),展開程式原始碼,可以發現,是Cview類提供標準列印和列印預覽選單命令的訊息處理函式:
設應用程式檢視類為CMyView,展開MyView.cpp,其訊息映象部分有如下兩行:
ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView::OnFilePrintPreview)
CView::OnFilePrint 和CView::OnFilePrintPreview函式都進行列印操作,但View::OnFilePrint將實際傳送到印表機,而CView::OnFilePrintPreview則將輸出傳送到程式視窗上方顯示的預覽視窗顯示一個或兩個列印頁面的複製外觀。利用上面加入的預設列印支援,只能列印或預覽圖形的一個列印頁面,一個頁中放不下的部分則放棄,為了加強程式,使它列印整個圖形,一頁中放不下的部分放在另一頁,可以通過覆蓋幾個列印期間呼叫的虛擬函式來完成。下圖說明了整個列印和列印預覽的過程,顯示了每個虛擬函式在程式中哪個部分呼叫。注意每列印一個頁面就要經歷圖中的一個迴圈。
下表列出了虛擬函式並介紹了各自完成的任務,由於MFC列印或列印預覽文件時都呼叫虛擬函式,所以定義的覆蓋函式既影響列印也影響列印預覽。
二、對話方塊程式列印及列印預覽的實現
以上是基於文件/檢視的應用程式的列印原理,可以根據需要從CView類派生出檢視類覆蓋列印及列印預覽過程中的CView類的虛擬函式來定製文件/檢視應用程式的列印及列印預覽。在實際中,有很多基於對話方塊的應用程式,也需要提供列印及列印預覽。但嚮導沒有給基於對話方塊應用程式的基本支援。有了以上知識,可以構造出無文件的檢視類,具體的實現時,增加三個類,用以支援列印及列印預覽。以下用一具體例項說明。
函式名() | 覆蓋函式可能完成的任務 |
CView::OnPreparePrinting() | 呼叫CprintInfo成員函式(如CprintInfo::SetMaxPage設定文件長度)或設定CprintInfo資料成員以影響Print對話方塊或列印預覽操作,然後呼叫DoPreparePrinting生成用於列印或列印預覽的裝置描述表(注意必須覆蓋OnPreparePrinting並呼叫DoPreparePrinting) --------------------- 作者:卡哥 來源:CSDN 原文:https://blog.csdn.net/L_Andy/article/details/8071768 版權宣告:本文為博主原創文章,轉載請附上博文連結! |
CView::OnBeginPrinting() | 分配專門用於列印的字型,畫筆、畫刷和其它物件,根據裝置描述表計算並設定文件長,在裝置描述表上存放所需的訊息(這是第一個訪問裝置描述表的的虛擬函式) |
CView::OnPrepareDC() | 設定列印當前頁面的文字或圖形屬性,修改檢視原點,以列印當前頁面,如果沒有設定文件長度,在文件末尾終止列印迴圈(CprintInfo::m_bContinuePrinting賦值FALSE) |
CView::OnPrint() | 呼叫OnDraw進行輸出;呼叫OnDraw前選擇OnBeginPrinting分配的字型,呼叫OnDraw後取消物件,列印只出現在文件列印版中的頁頭和頁尾,如果列印輸出與螢幕輸出的外觀不同, 在這裡列印,而不是呼叫OnDraw |
CView::OnEndPrinting() | 呼叫Cgdi::DeleteObject刪除OnBeginPrinting分配的物件 |
1.用MFC應用嚮導建立對話方塊應用程式,設主對話方塊類為CPrintPreviewDlg,在主對話方塊上放一按鈕,(標題:列印預覽,ID:IDC_PRINTPREVIEW_BUTTON),用類嚮導增加其BN_CLICKED的訊息響應函式OnPrintPreviewButton生成列印預覽介面
void CPrintPreviewDlg::OnPrintPreviewButton()
{
CPrintFrame* pf = new CPrintFrame(this);
}
2、增加新類:
用ClassWizard新建CPrintFrame類(基類CFrameWnd),功能上相當於文件/檢視的應用程式的框架視窗類。
用ClassWizard新建CPrintView類(基類CScrollView),功能上相當於文件/檢視的應用程式的檢視類。
增加CPrintPreviewView類(基類CPreviewView,注意在頭其定義標頭檔案中加入包含afxpriv.h),用於列印預覽介面的檢視類。
3、對新生成的各類修改如下:
CPrintFrame類:
①增加公有資料成員
CPrintPreviewDlg* m_pOldWnd; // 用於儲存主對話方塊物件;
CPrintView* m_pView; // 用於儲存檢視類物件;
②過載建構函式,儲存對主對話方塊物件指標,建立視窗
CPrintFrame::CPrintFrame(CPrintPreviewDlg* pOld)
{
m_pOldWnd = pOld;
if ( !Create(NULL, "列印預覽", WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, CRect(200, 200, 500, 500)))
TRACE0("Failed to create view window! \n");
}
③修改解構函式,讓主對話方塊顯示'
CPrintFrame::~CPrintFrame()
{
m_pOldWnd->ShowWindow(SW_SHOW);
}
④新增列印模式函式,設定A4紙縱向列印或橫向列印(可以選擇使用)
#define DMORIENT_PORTRAIT 1 //縱向
#define DMORIENT_LANDSCAPE 2 //橫向
void SetLandscapeMode(int PrintMode)
{
PRINTDLG pd;
pd.lStructSize=(DWORD)sizeof(PRINTDLG);
BOOL bRet=AfxGetApp()->GetPrinterDeviceDefaults(&pd);
if(bRet)
{
// protect memory handle with ::GlobalLock and ::GlobalUnlock
DEVMODE FAR *pDevMode=(DEVMODE FAR *)::GlobalLock(pd.hDevMode);
pDevMode->dmPaperSize=DMPAPER_A4; //將列印紙設定為A4
// set orientation to landscape
if(PrintMode==1) //縱向列印
pDevMode->dmOrientation = DMORIENT_PORTRAIT;
else if(PrintMode==2) //橫向列印
pDevMode->dmOrientation = DMORIENT_LANDSCAPE;
::GlobalUnlock(pd.hDevMode);
}
}
⑤用ClassWizard增加WM_Create訊息處理函式,關聯CPrintView檢視物件;呼叫其OnFilePrintPreview函式進行列印預覽(若要直接列印,可直接向其傳送訊息);隱藏主對話方塊。
nt CPrintFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
CCreateContext context;
context.m_pNewViewClass = RUNTIME_CLASS(CPrintView);
context.m_pCurrentFrame = this;
context.m_pCurrentDoc = NULL;
context.m_pLastView = NULL;
m_pView = STATIC_DOWNCAST(CPrintView, CreateView(&context));
if (m_pView != NULL)
{
m_pView->ShowWindow(SW_SHOW);
SetActiveView(m_pView);
// SetLandscapeMode(DMORIENT_LANDSCAPE);
}
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;
}
⑥新增WM_Close訊息處理函式
void CPrintFrame::OnClose()
{
// TODO: Add your message handler code here and/or call default
CPrintFrame* pf=(CPrintFrame*)::AfxGetMainWnd();
CWinApp *pApp=AfxGetApp();
pApp->m_pMainWnd = pf->m_pOldWnd;
pf->DestroyWindow();
// CFrameWnd::OnClose();
}
CPrintView類:
①修改建構函式:將座標射模式置為預設模式。
CPrintView::CPrintView()
{
m_nMapMode = MM_TEXT;
}
②增加訊息對映實現列印。
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
③過載虛擬函式OnPreparePrinting,呼叫DoPreparePrinting生成用於列印或列印預覽的裝置描述表。
BOOL CPrintView::OnPreparePrinting(CPrintInfo* pInfo)
{
// TODO: call DoPreparePrinting to invoke the Print dialog box
//pInfo->SetMaxPage(1);
return DoPreparePrinting(pInfo);
// return CLogScrollView::OnPreparePrinting(pInfo);
}
④增加公有函式OnFilePrintPreview,呼叫DoPrintPreview實現列印預覽,該函式需要傳入四個引數:列印預覽工具條資源ID,執行列印及列印預覽的檢視物件指標,列印預覽介面檢視類的 CRuntimeClass指標,列印預覽狀態類CPrintPreviewState物件指標。
void CPrintView::OnFilePrintPreview()
{
CPrintPreviewState* pState = new CPrintPreviewState;
pState->lpfnCloseProc = _AfxPrintPreviewCloseProc; //設定列印預覽視窗關閉時的呼叫函式
if (!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this, RUNTIME_CLASS(CPrintPreviewView), pState))
{
TRACE0("Error, DoPrintPreview failed. \n");
AfxMessageBox(AFX_IDP_COMMAND_FAILURE);
delete pState;
}
}
⑤一些其他函式的實現
void CPrintView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: 計算此檢視的合計大小
sizeTotal.cx = sizeTotal.cy = 100;
SetScrollSizes(MM_TEXT, sizeTotal);
}
void CPrintView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here
}
void CPrintView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// m_rectPrint = pInfo->m_rectDraw;
//進行列印的內容程式碼等;
CLogScrollView::OnPrint(pDC, pInfo);
}
⑥在PrintView.cpp檔案中增加全域性函式,_AfxMyPreviewCloseProc,當單擊列印預覽視窗關閉按鈕時被呼叫。
BOOL CALLBACK _AfxPrintPreviewCloseProc(CFrameWnd* pFrameWnd)
{
ASSERT_VALID(pFrameWnd);
CPrintPreviewView* pView = (CPrintPreviewView*)pFrameWnd->GetDlgItem(AFX_IDW_PANE_FIRST);
ASSERT_KINDOF(CPreviewView, pView);
pView->OnPreviewClose();
return FALSE;
}
CPrintPreviewView類:
手動新增類CPrintPreviewView繼承CPreviewView類,.h檔案如下~
#pragma once
#include "afxpriv.h"
#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 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_)
增加工具欄按鈕的訊息響應函式OnPreviewClose(),OnPreviewPrint() .cpp如下詳盡程式碼
#include "stdafx.h"
#include ".\mypreviewview.h"
#include "StatisticsCoverDlg.h"
#include ".\statisticscoverdlg.h"
#include "PrintFrame.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);// 控制條的命令狀態更新
}
void CMyPreviewView::OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView)
{
CPreviewView::OnEndPrintPreview(pDC, pInfo, point, pView);
}
void CMyPreviewView::OnPreviewClose()
{
CPrintFrame* pf=(CPrintFrame*)::AfxGetMainWnd();
CWinApp *pApp=AfxGetApp();
pApp->m_pMainWnd=pf->m_pOldWnd;
pf->DestroyWindow();
}
void CMyPreviewView::OnPreviewPrint()
{
m_pPrintView->SendMessage(WM_COMMAND, ID_FILE_PRINT);
}
至此,基於對話方塊應用程式的具有列印及列印預覽的基本支援已經生成,完全由新生成的三個類來支援。正如上一部分介紹的,可以在CMyView類中定義CView類的幾個在列印過程中虛擬函式(CView::OnPreparePrinting,CView::OnBeginPrinting,CView::OnPrepareDC,CView::OnPrint,CView::OnEndPrinting,具體內容可參見前一部分)來定製其列印或列印預覽的內容。也可以將實現列印或列印預覽新增的三個類,生成MFC擴充套件動態連結庫,以方便加入到程式中。
打完收功~~