900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > VS MFC对话框程序打印及打印预览的实现

VS MFC对话框程序打印及打印预览的实现

时间:2020-07-14 13:31:54

相关推荐

VS MFC对话框程序打印及打印预览的实现

VS MFC对话框程序打印及打印预览的实现

花了一个星期,研究了网上大量的MFC对话框打印及打印预览功能的demo之后,网上现有的版本都比较旧,所以选中了几个版本,合并修改,得到这个比较完美的最新版本,编译无错,成功运行。

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则将输出发送到程序窗口上方显示的预览窗口显示一个或两个打印页面的复制外观。利用上面加入的缺省打印支持,只能打印或预览图形的一个打印页面,一个页中放不下的部分则放弃,为了加强程序,使它打印整个图形,一页中放不下的部分放在另一页,可以通过覆盖几个打印期间调用的虚拟函数来完成。下图说明了整个打印和打印预览的过程,显示了每个虚拟函数在程序中哪个部分调用。注意每打印一个页面就要经历图中的一个循环。

二、对话框程序打印及打印预览的实现

以上是基于文档/视图的应用程序的打印原理,可以根据需要从CView类派生出视图类覆盖打印及打印预览过程中的CView类的虚拟函数来定制文档/视图应用程序的打印及打印预览。在实际中,有很多基于对话框的应用程序,也需要提供打印及打印预览。但向导没有给基于对话框应用程序的基本支持。有了以上知识,可以构造出无文档的视图类,具体的实现时,增加三个类,用以支持打印及打印预览。以下用一具体实例说明。

1.用MFC应用向导创建对话框应用程序,设主对话框类为CPrintPreviewDlg,在主对话框上放一按钮,(标题:打印预览,ID:IDC_PRINTPREVIEW_BUTTON),用类向导增加其BN_CLICKED的消息响应函数OnPrintPreviewButton生成打印预览界面

void CPrintPreviewDlg::OnPrintPreviewButton(){CPrintFrame* pf = new CPrintFrame(this);}

2、增加新类:

增加新类步骤:项目->增加新项->MFC->MFC类

用ClassWizard新建CPrintFrame类(基类CFrameWnd),功能上相当于文档/视图的应用程序的框架窗口类。

用ClassWizard新建CPrintView类(基类CScrollView),功能上相当于文档/视图的应用程序的视图类。

增加CPrintPreviewView类(基类CPreviewView,注意在头其定义头文件中加入包含afxpriv.h),用于打印预览界面的视图类。(如果没有基类CPreviewView,只有CPreviewViewEx基类,手动将CPreviewViewEx类改成基类CPreviewView)

3、对新生成的各类修改如下:

CPrintFrame类:

CPrintFrame.h:

#define WM_BEGIN_PRINTING (WM_USER+1004)

1、增加公有数据成员

CPrintPreviewDlg* m_pOldWnd; // 用于保存主对话框对象;CPrintView* m_pView; // 用于保存视图类对象;

2、重载构造函数,保存对主对话框对象指针,创建窗口

CPrintFrame.h:

CPrintFrame(); // 动态创建所使用的受保护的构造函数CPrintFrame(CPrintPreviewDlg* pOld);virtual ~CPrintFrame();

CPrintFrame.cpp:

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");}

3、修改析构函数,让主对话框显示

CPrintFrame::~CPrintFrame(){m_pOldWnd->ShowWindow(SW_SHOW);}

4、添加打印模式函数,设置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); } }

5、用类向导增加WM_Create消息处理函数(关联CPrintView视图对象;调用其OnFilePrintPreview函数进行打印预览(若要直接打印,可直接向其发送消息);隐藏主对话框。)

int CPrintFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CFrameWnd::OnCreate(lpCreateStruct) == -1)return -1;// TODO: 在此添加您专用的创建代码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_RESTORE);CWinApp *pApp = AfxGetApp();pApp->m_pMainWnd = this;m_pView->OnFilePrintPreview();//打印预览m_pView->SendMessageW(WM_COMMAND, ID_FILE_PRINT); // 直接打印m_pOldWnd->ShowWindow(SW_SHOW);return 0;}

6、添加WM_Close消息处理函数`

void CPrintFrame::OnClose(){// TODO: Add your message handler code here and/or call defaultCPrintFrame* pf=(CPrintFrame*)::AfxGetMainWnd(); CWinApp *pApp=AfxGetApp();pApp->m_pMainWnd = pf->m_pOldWnd; pf->DestroyWindow();// CFrameWnd::OnClose();}

7、添加WM_DESTROY消息处理函数

{if (m_pView != NULL)m_pView->DestroyWindow();CFrameWnd::OnDestroy();CFrameWnd::OnDestroy();}

CPrintView类:

①修改构造函数:将坐标射模式置为缺省模式。

CPrintView::CPrintView(){m_nMapMode = MM_TEXT;}

②增加消息映射实现打印。

BEGIN_MESSAGE_MAP(CPrintView, CScrollView)ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)END_MESSAGE_MAP()

③重载虚函数OnPreparePrinting,调用DoPreparePrinting生成用于打印或打印预览的设备描述表。

BOOL CPrintView::OnPreparePrinting(CPrintInfo* pInfo){return DoPreparePrinting(pInfo);}

④增加公有函数OnFilePrintPreview,调用DoPrintPreview实现打印预览,该函数需要传入四个参数:打印预览工具条资源ID,执行打印及打印预览的视图对象指针,打印预览界面视图类的 CRuntimeClass指针,打印预览状态类CPrintPreviewState对象指针。

void CPrintView::OnFilePrintPreview(){// TODO: 在此处添加实现代码.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();}void CPrintView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo){// TODO: 在此添加专用代码和/或调用基类CView::OnBeginPrinting(pDC, pInfo);CPrintFrame *pFrame = (CPrintFrame *)GetParent();pFrame->m_pOldWnd->SendMessage(WM_BEGIN_PRINTING, (WPARAM)pDC, (LPARAM)pInfo);}void CPrintView::OnEndPrinting(CDC* pDC, CPrintInfo* pInfo){// TODO: 在此添加专用代码和/或调用基类CScrollView::OnEndPrinting(pDC, pInfo);if (m_fontPrinter.m_hObject != NULL)m_fontPrinter.DeleteObject();return;}

⑥在PrintView.cpp文件中增加全局函数,_AfxMyPreviewCloseProc,当单击打印预览窗口关闭按钮时被调用。

BOOL CPrintView::_AfxPrintPreviewCloseProc(CFrameWnd * pFrameWnd){ASSERT_VALID(pFrameWnd);CPrintPreviewView* pView = (CPrintPreviewView*)pFrameWnd->GetDlgItem(AFX_IDW_PANE_FIRST);ASSERT_KINDOF(CPreviewView, pView);pView->OnPreviewClose();return FALSE;}

7、增加公有函数OnPrint(CDC* pDC, CPrintInfo* pInfo),添加自己需要打印的文字和图片。

CPrintView.h:

CDC* m_dc;int m_page_v_margin;//纵向边距int m_page_h_margin;//横向边距int m_page_height;//页高,包括marginint m_page_width;//页宽,包括marginint m_current_y_pos;//纵向当前打印到哪个位置了,如果到了页底部要调用EndPage重新开一页int m_line_height;//行高,包括字体高度和行间距int m_v_dist;//行间距BOOL m_is_printing_page;//正在打印页BOOL m_mission_started;//打印任务已经开始BOOL m_need_start_new_page;//需要开始新的一页int m_max_page;//总页码int m_page_number;//当前页码int m_total_line_number; //要打印的内容的总行数,不包括页脚页眉,只包括数据行int m_max_line_count_one_page;CString m_doc_name;//页眉文字

CPrintView.cpp:

void CPrintView::OnPrint(CDC* pDC, CPrintInfo* pInfo){// TODO: 在此添加专用代码和/或调用基类CScrollView::OnPrint(pDC, pInfo);m_dc = pDC;m_page_v_margin = 0;m_page_h_margin = 0;m_page_height = 0;m_current_y_pos = 0;m_line_height = 0;m_is_printing_page = FALSE;m_mission_started = FALSE;m_page_number = 0;m_max_page = 0;m_total_line_number = 0;m_v_dist = 2;m_max_line_count_one_page = 0;m_doc_name = AfxGetAppName();m_need_start_new_page = TRUE;TEXTMETRIC tm;m_dc->GetTextMetrics(&tm);m_line_height = tm.tmHeight + tm.tmInternalLeading;m_page_v_margin = m_dc->GetDeviceCaps(LOGPIXELSY) / 2;m_page_h_margin = m_dc->GetDeviceCaps(LOGPIXELSX) / 2;m_page_height = m_dc->GetDeviceCaps(VERTRES);m_page_width = m_dc->GetDeviceCaps(HORZRES);m_current_y_pos = m_page_v_margin;//求出页数m_max_line_count_one_page = (int)((m_page_height - m_page_v_margin * 2 - 50) / (m_line_height + 50));m_max_page = (int)(m_total_line_number / m_max_line_count_one_page);if (m_max_page*m_max_line_count_one_page < m_total_line_number) m_max_page++;//UINT gl_uNumOfPoints = 52;//CDC* pDC = (CDC*)wParam;//CPrintInfo* pInfo = (CPrintInfo *)lParam;int nPageNumber = pInfo->m_nCurPage;int i, j;CFont *pOldFont;CFont DataFont;DataFont.CreatePointFont(120, _T("宋体"), m_dc);pOldFont = m_dc->SelectObject(&DataFont);if (1){TCHAR *pszTitle[200] = { _T("编号"),_T("数值1"),_T("数值2"),_T("数值3"),_T("数值4"),_T("数值5"),_T("数值6") };pOldFont = m_dc->SelectObject(&DataFont);//画矩形m_dc->Rectangle(m_page_h_margin, m_page_v_margin, m_page_width - m_page_h_margin, m_page_height - m_page_v_margin);//bottomfor (int i = 0; i<7; i++){m_dc->TextOut(m_page_h_margin + 50 + i * (m_page_width - m_page_h_margin * 2) / 7,4 * m_line_height,CString(pszTitle[i]));}m_dc->SelectObject(pOldFont);}}

CPrintPreviewView类:

手动修改添加类CPrintPreviewView继承CPreviewView类

CPrintPreviewView.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>// CPrintPreviewView 视图class CPrintPreviewView : public CPreviewView{DECLARE_DYNCREATE(CPrintPreviewView)protected:CPrintPreviewView(); // 动态创建所使用的受保护的构造函数virtual ~CPrintPreviewView();public:#ifdef _DEBUGvirtual void AssertValid() const;#ifndef _WIN32_WCEvirtual void Dump(CDumpContext& dc) const;#endif#endifpublic:afx_msg void OnPreviewClose();protected:afx_msg void OnPreviewPrint();DECLARE_MESSAGE_MAP()virtual void OnDraw(CDC* pDC);virtual void OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView);};

增加工具栏按钮的消息响应函数OnPreviewClose(),OnPreviewPrint() .cpp如下详尽代码

#include "stdafx.h"#include "PrintPreview.h"#include "CPrintPreviewView.h"#include "CPrintFrame.h"// CPrintPreviewViewIMPLEMENT_DYNCREATE(CPrintPreviewView, CPreviewView)CPrintPreviewView::CPrintPreviewView(){}CPrintPreviewView::~CPrintPreviewView(){}BEGIN_MESSAGE_MAP(CPrintPreviewView, CPreviewView)ON_COMMAND(AFX_ID_PREVIEW_CLOSE, OnPreviewClose)ON_COMMAND(AFX_ID_PREVIEW_PRINT, OnPreviewPrint)END_MESSAGE_MAP()// CPrintPreviewView 诊断#ifdef _DEBUGvoid CPrintPreviewView::AssertValid() const{CPreviewView::AssertValid();}#ifndef _WIN32_WCEvoid CPrintPreviewView::Dump(CDumpContext& dc) const{CPreviewView::Dump(dc);}void CPrintPreviewView::OnPreviewClose(){CPrintFrame* pf = (CPrintFrame*)::AfxGetMainWnd();CWinApp *pApp = AfxGetApp();pApp->m_pMainWnd = pf->m_pOldWnd;pf->DestroyWindow();}void CPrintPreviewView::OnPreviewPrint(){m_pPrintView->SendMessage(WM_COMMAND, ID_FILE_PRINT);}#endif#endif //_DEBUG// CPrintPreviewView 消息处理程序void CPrintPreviewView::OnDraw(CDC* pDC){// TODO: 在此添加专用代码和/或调用基类CPreviewView::OnDraw(pDC);m_pToolBar->PostMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE);// 控制条的命令状态更新}void CPrintPreviewView::OnEndPrintPreview(CDC* pDC, CPrintInfo* pInfo, POINT point, CPreviewView* pView){// TODO: 在此添加专用代码和/或调用基类CPreviewView::OnEndPrintPreview(pDC, pInfo, point, pView);}

最终结果图;

程序链接:/download/weixin_42403113/11069726

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。