基于MFC对话框的报表打印和预览功能(推荐文档)
- 格式:doc
- 大小:35.01 KB
- 文档页数:5
mfc打印功能的实现怎样用MFC实现打印功能?最佳答案int count=this->m_logList.GetItemCount(),page,row=0;int i,j;page=count/40+1;CPrintDialog print(false);if(print.DoModal()==IDOK){CDC printed;printed.Attach(print.GetPrinterDC());DOCINFO pdoc;pdoc.cbSize=sizeof(pdoc);pdoc.lpszDocName=L"pdoc";pdoc.lpszDatatype=NULL;pdoc.fwType=NULL;pdoc.lpszOutput=NULL;if(printed.StartDoc(&pdoc)>=0){LOGFONT logfont;memset(&logfont,0,sizeof(LOGFONT));logfont.lfHeight=75;CFont font;CFont *oldfont=NULL;if(font.CreateFontIndirect(&logfont))oldfont=(CFont*)printed.SelectObject(&font);for(j=1;j<=page;j++){printed.StartPage();int x=500,y=400;//A4纸,页面中的位置,横向为x轴,纵向是y轴,A4 maxX=4000 maxY=7000 建议按字符大小为75,每页安排40条纪录,初试纪录开始位置为x=500 y=200CString pageHead,pageBottom;pageHead.Format(_T("日志信息纪录统计表"));printed.TextOut(1500,100,pageHead); //打印页眉CString title;//设置标题栏title.Format(_T("序号时间操作"));printed.TextOut(500,200,title); //打印页眉CString stt;stt.Format(_T("________________________________________________ __ ____________________________________"));printed.TextOut(500,200+80,stt); //打印页眉for(i=1;(i<40)&&(row<count);i++)< bdsfid="100" p=""></count);i++)<>{CString record(_T(""));record+=this->m_logList.GetItemText(row,0)+L" ";record+=this->m_logList.GetItemText(row,1)+L" ";record+=this->m_logList.GetItemText(row,2);printed.TextOut(x,y,record);y+=80;printed.TextOut(x,y,stt);y+=80;row++;}pageBottom.Format(_T("共%d页第%d页"),page,j);printed.TextOut(1500,y,pageBottom);printed.EndPage();//此页结束}font.DeleteObject();if(oldfont!=NULL)printed.SelectObject(oldfont);printed.EndDoc();}printed.DeleteDC();}MFC简单打印方法2001-04-06· ·vc.faq··yesky通过MFC来完成打印作业有很多的方法,应用场合也有所不同。
使用MFC操作EXCEL文件本文档适用于:•Microsoft Foundation Classes (MFC), Microsoft Visual C++, 32-bit Editions, version 6.0 以上•Microsoft OLE 库第一步:建立一个自动化工程1.启动VC 6.0,打开新建对话框,新建一个MFC AppWizard(exe)工程,这里工程明设置为TestExcel。
2.进入MFC 应用程序向导,选择基本对话框,直接点击完成,工程文件结构如下图:3.打开MFC ClassWizard窗口(查看—>建立类向导),选择Automation,单击AddClass按钮,选择From a type library...,弹出文件选择对话框,之后定位到Microsoft Office的安装目录(通常为C:\Program Files\Microsoft Office\Office),选择EXCEL9.OLB注意,确定后,弹出Confirm Classes窗口,选择列表中的所有类,单击OK按钮。
注意文件名EXCEL9.OLB,因安装的Office版本不同而有所差异,EXCEL9.OLB对应的是Microsoft Office 2000,微软命名方式为Excel+数字的形式,Office版本越高,数字越大。
4.返回编辑器,查看工程文件,可发现多了EXCEL9.H及EXCEL9.CPP两个文件。
5.打开stdafx.h头文件确保包含如下头文件:#include <afxdisp.h>#include "excel9.h"6.打开TestExcel.cpp文件,修改CTestExcelApp::InitInstance(),加入如下代码:BOOL CTestExcelApp::InitInstance(){if( !AfxOleInit() ){AfxMessageBox("初始化Ole出错!");return FALSE;}AfxEnableControlContainer();............return FALSE;}为保证编译时不产生重复定义错误,打开excel9.h文件,在文件开始位置加入如下代码:#if !defined _HEAD_FILE_EXCEL9_#define _HEAD_FILE_EXCEL9_相应的,在文件末尾加入:#endif到此,OLE自动化工程建立完成。
实验八MFC中的对话框及控件(二)实验目的掌握常用的控件使用方法以及基于对话框的应用程序的开发实验内容1、编辑框的使用2、选择按钮的使用3、下拉列表的使用4、按钮的使用5、基于对话框的应用程序开发一、编辑框的使用[实验步骤]1、新建一个MFC单文档项目;2、在资源选项卡中插入一个自己的对话框3、新建一个对话框模板4、在对话框中添加2个静态文本控件和2个编辑框控件。
注意这2个编辑框控件的ID5、通过Classwizzard添加数据成员。
在Classwizzard弹出的对话框中选择新建你这个对话框的类,取名叫“Cmydlg”,当然你也可以取其他名字选择成员变量选项卡,然后双击某个编辑框的ID,设置对应数据成员名字及类型。
6、在你的工程的view类的头部通过包含对话框类的头文件#include “mydlg.h”包含你所建的对话框类。
注意:如果你改了对话框类的名字,看看相应的项目里新增的那个类的头文件名7、在View类中增加2个变量CString myname;int myage;8、通过Classwizzard增加一个鼠标左键消息响应函数,并在函数中增加如下代码:void CT estView::OnLButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultCmydlg dlg;if(dlg.DoModal()==IDOK){myname=dlg.m_name;myage=dlg.m_age;Inavalidate();}CView::OnLButtonDown(nFlags, point);}9、在OnDraw函数里增加如下显示内容的代码CString str;str.Format("我的姓名是%s",myname);pDC->TextOut(10,10,str);str.Format("我的年龄是%d",myage);pDC->TextOut(10,30,str);10、编译运行程序,在工作视图区点鼠标左键二、选择按钮的使用[实验步骤]1、新建一个MFC单文档项目;2、在资源选项卡中插入一个自己的对话框3、新建一个对话框模板4、在对话框中添加3个单选框控件。
MFC打印与打印预览(1)Programming Windows 95 with MFC, Part VIII: Printing and Print PreviewingJeff ProsiseJeff Prosise writes extensively about programming in Windows and is a contributing editor of several computer magazines. He is currently working on a book, Programming Windows 95 with MFC, tobe published this spring by Microsoft Press.Click to open or copy the EZPRNT project files.Click to open or copy the HEXDUMP project files.I demonstrated previously ("Programming Windows® 95 with MFC, Part VII: The Document/View Architecture," MSJ, February 1996) how the document/view architecture simplifies the development of SDI and MDI applications by letting the framework take over key aspects of a program's operation. Now I'll show you how the same document/view architecture simplifies printing and print previewing. Even MFC-style printing isn't something to be taken lightly, but thanks to the support lent by the framework, the tedium of writing and testing code that renders documents on printers and other hardcopy devices is sharply reduced. And once you've implemented Print, Print Preview comes almost for free.Documents and ViewsThe MFC print architecture is built around core API print functions and protocols built into the Windows GDI. To understand what's on the outside, it helps to first understand what's on the inside. Inthis article I will:∙Discuss the Windows printing model and examine the steps an SDK-style application goes through toprint a document.∙Describe the relationship between the MFC print architecture and the Windows print architecture, and the mechanics of printing from MFC applications, including key virtual functions you can override in yourview class.∙Develop a bare-bones printing program that demonstrates how the same code can be used to sendoutput to the screen or printer.∙Develop a more ambitious program with print and preview capabilities on par with those ofcommercial applications. (Sounds pretty good, huh?)The Windows Print ArchitecturePrinting a document from a Windows-based application without the benefit of the framework involves a number of grueling steps. The application normally begins by obtaining a device context for the printer. Just as you need a screen DC to send output to the screen, you need a printer DC to send output to a printer. If you know the device name of the printer you want, you can create a device context with the ::CreateDC function in Windows or CDC::CreateDC in MFC.CDC dc;dc.CreateDC (NULL, "HP LaserJet IIP", NULL, NULL);The device name specified in the second parameter is the same one that appears in the control panel and Print Setup dialog. By the way, this syntax is simpler than Windows 3.1, which requires the driver name and other information. If you don't know the device name but would like to print to the default printer (the one whose context menu has a check mark by the "Set As Default" menu item), you can use the handy MFC CPrintDialog::GetDefaults and CPrintDialog::GetPrinterDC functions.CDC dc;CPrintDialog dlg (FALSE);dlg.GetDefaults ();dc.Attach (dlg.GetPrinterDC ());If you'd like to let the user select a printer, you can display a Print dialog (one of the commondialogs supplied for you by the operating system) with CPrintDialog::DoModal, then callCPrintDialog::GetPrinterDC after the dialog is dismissed.CDC dc;CPrintDialog dlg (FALSE);if (dlg.DoModal () == IDOK)dc.Attach (dlg.GetPrinterDC ());A printer device context obtained by any of these methods should be deleted when it's no longerneeded. If you create a CDC object on the stack, deletion is automatic.Once you have a printer DC in hand, you're ready to print. The next step is to call ::StartDoc or its MFC equivalent, CDC::StartDoc, to mark the beginning of the print job. CDC::StartDoc accepts just one parameter: a pointer to a DOCINFO structure containing a string with a descriptive name for the document that's about to be printed, the name of the file that output will go to (if you're printing to a file), and other information about the print job. The statementsDOCINFO di;::ZeroMemory (&di, sizeof (DOCINFO));di.cbSize = sizeof (DOCINFO);di.lpszDocName = "Budget Figures for the Current FiscalYear";dc.StartDoc (&di);start a print job on the printer associated with the CDC object dc. If the user examines the print queue while the document is printing, the string "Budget Figures for the Current Fiscal Year" will appear in the Document Name column. If StartDoc fails, it returns a zero or less-than-zero value. If it succeeds, it returns a positive integer that identifies the print job. The print job ID can be used in conjunction with Win32® print-control functions such as ::GetJob and ::SetJob.Next comes output to the printed page. Text and graphics are rendered on a printer with GDI functions. If dc refers to a screen device context, the statementdc.Ellipse (0, 0, 100, 100);draws an ellipse 100 logical units wide and 100 logical units high on the screen (that is, a circle). If dc refers to a printer device context, the circle is drawn on the printer instead. Pages of output are framed between calls to CDC::StartPage and CDC::EndPage that mark the beginning and end of each page. A document that contains nPageCount pages of output could be printed as follows:dc.StartDoc (&di);for (int i=1; i<=nPageCount; i++) {dc.StartPage ();// Print page idc.EndPage ();}In a very simplified sense, calling EndPage is like sending a form-feed character to the printer. In between StartPage and EndPage, you print the page by calling CDC member functions. Even if the document contains only one page, you must call StartPage and EndPage.One mistake programmers often make the first time they write printing code is that they fail to initialize the printer DC for each page. In Windows 95, the device context's default attributes are restored each time you call StartPage. You can't select a font or set the mapping mode right after the DC is created and expect those attributes to remain in effect indefinitely the way you can for a screen DC. Instead, you must reinitialize the printer DC for each page. (In Windows NTÔ 3.5 and later, a printer DC retains its settings across calls to StartPage and EndPage—but even in a Windows NT-based application, you should reinitialize the device context at the beginning of each page if you want your code to work under Windows 95 too.) If you print using the MM_LOENGLISH mapping mode, for example, you must call CDC::SetMapMode at the beginning of each new page.for (int i=1; i<=nPageCount; i++) {dc.StartPage ();dc.SetMapMode (MM_LOENGLISH);// Print page idc.EndPage ();}If you do it this way instead,// Don't do this!dc.SetMapMode (MM_LOENGLISH);for (int i=1; i<=nPageCount; i++) {dc.StartPage ();// Print page idc.EndPage ();}printing will be performed in the default MM_TEXT mapping mode.After the final page is printed, you terminate the print job by calling CDC::EndDoc—unless a previous call to EndPage returned a code indicating that the print job was already terminated by GDI. EndPage returns a signed integer value that is greater than zero if the page was successfully printed. A zero or negative return value indicates that either an error occurred or the user canceled the print job while the page was being printed. In either event, the return value is one of the codes shown in Figure 1.Figure 1 Printing Return CodesReturn Code DescriptionSP_ERROR The print job was aborted for an unspecified reasonSP_APPABORT The print job was aborted because the user clicked the Cancel button in the dialog box that displays the status of the print jobSP_USERABORT The print job was aborted because the user canceled it through the operatingsystem shellSP_OUTOFDISK The system is out of disk space, so no further printer data can be spooledSP_OUTOFMEMORY The system is out of memory, so no further printer data can be spooledThe following loop demonstrates the correct use of EndDoc.if (dc.StartDoc (&di) > 0) {BOOL bContinue = TRUE;for (int i=1; i<=nPageCount && bContinue; i++) {dc.StartPage ();// Initialize the device context// Print page iif (dc.EndPage () <= 0)bContinue = FALSE;}if (bContinue)dc.EndDoc ();elsedc.AbortDoc ();}CDC::AbortDoc aborts an uncompleted print job just as EndDoc ends a successful print job. You can also call AbortDoc at any time to terminate a print job before the job is done.The Abort Procedure and Abort DialogIf that's all there were to printing, it wouldn't be such a big deal. But there's more; because a large print job can take minutes or even hours to complete, the user should be able to terminate a print job before it is finished. Windows-based applications traditionally let the user cancel a print job by clicking a Cancel button in a dialog box. The Cancel button cancels printing by forcing EndPage to returnSP_APPABORT.The mechanism that links the Cancel button to the printing code in your application is a function that Windows calls an "abort procedure." An abort procedure is an exported callback function that Windows calls repeatedly as it processes printed output. It's declared like this:BOOL CALLBACK AbortProc (HDC hDC, int nCode)hDC holds the handle of the printer device context. nCode is zero if printing is proceeding smoothly or SP_OUTOFDISK if the print spooler is temporarily out of disk space. nCode is usually ignored because the print spooler responds to an SP_OUTOFDISK condition by waiting for more disk space tofree up. The abort procedure's job is twofold:∙To check the message queue with ::PeekMessage and retrieve and dispatch any messages waitingfor the application.∙To tell Windows whether printing should continue by returning TRUE (to continue printing) or FALSE(to abort).A very simple abort procedure looks like this:BOOL CALLBACK AbortProc (HDC hDC, int nCode)MSG msg;while (::PeekMessage (&msg, NULL, 0, 0,PM_NOREMOVE))AfxGetThread ()->PumpMessage ();return TRUE;}The message loop inside AbortProc allows the WM_COMMAND message (generated when the print-status dialog's Cancel button is clicked) to make it to your window procedure even though the application is busy printing. In 16-bit Windows, the message loop plays an important role in multitasking by yielding so the print spooler and other processes running in the system can get CPU time. In Windows 95, yielding in the abort procedure enhances multitasking performance when 32-bit applications print to 16-bit printer drivers by reducing contention for the Win16Mutex—the flag inside Windows that locks 32-bit applications out of the 16-bit kernel while a 16-bit application executes code in the kernel.Before calling StartDoc, the application calls SetAbortProc to set the abort procedure, then disables its own window by calling CWnd::EnableWindow (FALSE), and displays the print-status or "abort" dialog—a modeless dialog containing a Cancel button and usually one or more static controls to show the document name and number of pages printed. Disabling the main window ensures that no other input will interrupt the printing process. The window is reenabled when printing is finished and the dialog box is destroyed. The dialog, meanwhile, sets a flag—call it bUserAbort—from FALSE to TRUE if the Cancel button is clicked, and the abort procedure returns FALSE to abort printing if bUserAbort isTRUE.BOOL CALLBACK AbortProc (HDC hDC, int nCode){MSG msg;while (!bUserAbort &&::PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))AfxGetThread ()->PumpMessage ();return !bUserAbort;Printing proceeds unimpeded until/unless the user cancels, whereupon bUserAbort changes from FALSE to TRUE, the next call to AbortProc returns zero, and Windows terminates the print job. EndPage returns SP_APPABORT and the call to EndDoc is subsequently bypassed.Print SpoolingEverything I've described up to this point constitutes the "front end" of the printing process—the portion that the application is responsible for. Windows handles the back end, which is a joint effort on the part of GDI, the print spooler, the printer driver, and other components of the 32-bit print subsystem. If enhanced metafile (EMF) print spooling is enabled, GDI calls executed through the printer DC are written to an enhanced metafile on the hard disk and stored there until the print spooler, which runs in a separate thread, unspools the commands and "plays" them into the printer driver. If "raw" print spooling (the only option on PostScript printers) is enabled instead, output is processed through the printer driver and spooled to disk in raw form. If spooling is disabled, GDI commands are transmitted directly to the printer driver each time EndPage is called. Print spooling speeds the return-to-application time by letting a program do all its printing to a metafile so the user doesn't have to wait for the printer to physically print each page. Metafiles further speed things up by decoupling the performance of the application from the performance of the printer driver. That's one reason why Windows 95 seems to print so much faster than Windows 3.1. In Windows 3.1, GDI commands are processed by the printer driver before they're spooled to disk. In Windows 95, output is spooled first and played through the printer driver later, so the translation of GDI commands into device-dependent printer data is performed entirely in the background.Fortunately, you can safely ignore what happens on the back end of the printing process and concentrate on printing your document. Still, there's a host of details to fret before you can get down to the real business of printing—paginating the output and executing GDI calls between StartPage and EndPage to render each page on the printer. With this background in mind, let's see how MFC makesprinting easier.The MFC Print ArchitectureThe simplified print architecture in MFC is just one more reason that programmers are migrating away from the SDK and toward object-oriented development environments such as Visual C++®. When you print from a document/view application, you can forget about most of the code samples in the previous section. The framework creates a printer DC for you and deletes the DC when printing is finished. The framework also calls StartDoc and EndDoc to begin and end the print job, and StartPage and EndPage to bracket GDI calls for each page. It even supplies a Cancel dialog and abort procedure.In some cases, the very same OnDraw function you use to render your document on screen can doprinting and Print Preview too.The key to printing in document/view is a set of virtual CView functions that the framework calls at various stages during the printing process. These functions are summarized in Figure 2. Which CView functions you override and what you do in the overrides is highly dependent upon the content of yourprinted output. At the very least, you must override OnPreparePrinting to call DoPreparePrinting so the framework will display a Print dialog and create a printer DC.BOOL CMyView::OnPreparePrinting (CPrintInfo* pInfo){return DoPreparePrinting (pInfo);}Figure 2 CView Print OverridablesFunction DescriptionCView::OnPreparePrinting Called at the very onset of a print job. Override to callCView::DoPreparePrinting and provide the framework with the page count (ifknown) and other information about the print job.CView::OnBeginPrinting Called just before printing begins. Override to allocate fonts and otherresources required for printing.CView::OnPrepareDC Called before each page is printed. Override to set the viewport origin orclipping region to print the current page if OnDraw will be used to produce theprinted output.CView::OnPrint Called to print one page of the document. A page number and printer DC aresupplied to you by the framework. Override to print headers, footers, andother page elements that aren't drawn by the view's OnDraw function or toprint each page without relying on OnDraw.CView::OnEndPrinting Called when printing is finished. Override to deallocate resources allocated inOnBeginPrinting.A nonzero return from OnPreparePrinting begins the printing process, while a zero return cancelsthe pending print job. DoPreparePrinting returns zero if the user cancels the print job by clicking the Cancel button in the Print dialog, if there are no printers installed, or if the framework is unable to create aprinter DC.More on OnPreparePrintingThe CPrintInfo object passed to OnPreparePrinting contains information describing the parameters of the print job, including the minimum and maximum page numbers. The minimum and maximum page numbers default to 1 and 0xFFFF, with the latter value signaling to the framework that the maximum page number is unknown. If you know how many pages your document has, you should callCPrintInfo::SetMaxPage before calling DoPreparePrinting.BOOL CMyView::OnPreparePrinting (CPrintInfo* pInfo){pInfo->SetMaxPage (nMaxPage);return DoPreparePrinting (pInfo);}The framework, in turn, will display the maximum page number in the "to" box of the Print dialog.SetMaxPage is one of several CPrintInfo member functions you can call to set printing parameters or query the framework about print options entered by the user. SetMinPage lets you specify the minimum page number. GetMinPage and GetMaxPage return the minimum and maximum page numbers, while GetFromPage and GetToPage return the starting and ending page numbers entered in the Print dialog's "from" and "to" boxes. CPrintInfo also includes several public data members, including m_pPD, which points to the initialized CPrintDialog object. You can use this pointer to customize the Print dialog before it's displayed, or get information from it. I'll show you an example of this later in the article.OnBeginPrinting and OnEndPrintingOften the maximum page number depends on the size of the printable area of each page. Unfortunately, you don't know what that is until after the user has selected a printer and the framework has created a printer DC. If you don't set the maximum page number in OnPreparePrinting, you should set it in OnBeginPrinting if at all possible. OnBeginPrinting receives a pointer to an initialized CPrintInfo structure and a pointer to a CDC object representing the printer DC. You can determine the dimensions of the printable page area by calling CDC::GetDeviceCaps twice—once with a HORZRES parameter,and once with a VERTRES parameter.void CMyView::OnBeginPrinting (CDC* pDC,CPrintInfo* pInfo){int m_nPageHeight = pDC->GetDeviceCaps (VERTRES);int nDocLength = GetDocument ()->GetDocLength ();int nMaxPage = max (1, (nDocLength +(m_nPageHeight - 1)) /m_nPageHeight);pInfo->SetMaxPage (nMaxPage);}In this example, GetDocLength is a document function that returns the length of the document in pixels. CPrintInfo contains a data member, m_rectDraw, that describes the printable page area in logical coordinates—but don't try to use it in OnBeginPrinting because it isn't initialized until shortly beforeOnPrint is called.Calling SetMaxPage in either OnPreparePrinting or OnBeginPrinting lets the framework know how many times it should call OnPrint to print a page. If it's impossible (or simply not convenient) to determine the document length before printing begins, you can perform "print-time pagination" by overriding OnPrepareDC and setting CPrintInfo::m_bContinuePrinting to TRUE or FALSE each time OnPrepareDC is called. FALSE terminates the print job. If you don't call SetMaxPage, the framework assumes the document is only one page long. Therefore, you must override OnPrepareDC and setm_bContinuePrinting to print additional pages.OnBeginPrinting is also the best place to create fonts and other GDI resources that you need to print. Suppose your view's OnCreate function creates a font that OnDraw uses to draw text on the screen, and the font height is based on screen metrics returned by GetDeviceCaps. To print a WYSIWYG version of that font on the printer, you must create a separate font that's scaled to printer metrics rather than screen metrics. One solution is to let OnDraw create the font each time it's used so the font is scaled for whatever device the CDC corresponds to—printer or screen. An alternative solution is to create the printer font in OnBeginPrinting and delete it in OnEndPrinting. Then you avoid the extra overhead ofcreating and deleting a font each time OnDraw is called.OnEndPrinting is the counterpart to OnBeginPrinting. It's a great place to free fonts and other resources allocated in OnBeginPrinting. If there are no resources to free, or if you didn't override OnBeginPrinting to begin with, then you probably don't need to override OnEndPrinting either.OnPrepareDCMFC calls OnPrepareDC once for each page of your document. One reason for overriding OnPrepareDC is to perform print-time pagination as described in the previous section. Another reason is to calculate a new viewport origin from the current page number so OnDraw will render the appropriate page in your document. Like OnBeginPrinting, OnPrepareDC receives a pointer to a device context and a pointer to a CPrintInfo object. Unlike OnBeginPrinting, OnPrepareDC is called prior to screen repaints as well as in preparation for outputting a page to the printer. In the case of screen rendering, the CDC pointer refers to a screen DC and the CPrintInfo pointer is NULL. For printing, the CDC pointer is a printer DC and the CPrintInfo pointer is non-NULL. In the latter case, the number of the page that's about to beprinted can be obtained from CPrintInfo::m_nCurPage. You can determine whether OnPrepareDC was called for the screen or printer by calling CDC::IsPrinting.The following implementation of OnPrepareDC moves the viewport origin in the y direction so the device point (0, 0)—the pixel in the upper-left corner of the printed page—corresponds to the upper-left corner of the current page. m_nPageHeight is a CMyView data member that holds the printable pageheight.void CMyView::OnPrepareDC (CDC* pDC, CPrintInfo* pInfo){CView::OnPrepareDC (pDC, pInfo);if (pDC->IsPrinting ()) { // If printing...int y = (pInfo->m_nCurPage- 1) * m_nPageHeight;pDC->SetViewportOrg (0, -y);}}Setting the viewport origin this way ensures that an OnDraw function attempting to draw the entire document will actually only draw the portion that corresponds to the current page. This is a simple example of OnPrepareDC that assumes you want to use the entire printable area of the page. Sometimes it's also necessary to set a clipping region to restrict the printed portion of the document to something less than the page's full printable area. Rectangular regions are created with CRgn::CreateRectRgn and selected into DCs to serve as clipping regions with CDC::SelectClipRgn.As a rule, you only need to override OnPrepareDC to print multipage documents for which OnDraw does the printing. If you do all of your printing from OnPrint, as one of my sample programs does, then there's no need to override OnPrepareDC. When you do override OnPrepareDC, you should call the base class before doing anything else so the default implementation will get a chance to do its thing. This is especially important when your view class is derived from CScrollView, because CScrollView::OnPrepareDC sets the viewport origin for screen DCs to match the current scroll position. When CScrollView::OnPrepareDC returns, the DC's mapping mode is set to the mapping mode specified when you called SetScrollSizes. If your view class is not derived from CScrollView, OnPrepareDC is agood place to call SetMapMode.OnPrintAfter calling OnPrepareDC, but prior to physically printing each page, the framework calls CView::OnPrint. The default implementation in Viewcore.cpp verifies the validity of pDC and passes thebuck to OnDraw.void CView::OnPrint(CDC* pDC, CPrintInfo*){ASSERT_VALID(pDC);// Override and set printing variables based on// page numberOnDraw(pDC); // Call Draw}If you prepared the printer DC for printing in OnPrepareDC, or if the document contains only one page, you don't have to override OnPrint; you can let the default implementation call OnDraw to do theprinting.In practice, OnPrint is frequently overridden to perform page-specific printing tasks. Probably the most common reason to override OnPrint is to print headers, footers, page numbers and other visual elements that appear on the printed page but not on the screen (with the exception of print previews). The following OnPrint function calls local member functions PrintHeader and PrintPageNumber to print a header and page number before calling OnDraw to print the page:void CMyView::OnPrint (CDC* pDC, CPrintInfo* pInfo){PrintHeader (pDC);PrintPageNumber (pDC, pInfo->m_nCurPage);// Set the viewport origin and/or clipping// region before calling OnDraw...OnDraw (pDC);}Note that any adjustments made to the printer DC with SetViewportOrg or SelectClipRgn should now be made in OnPrint rather than OnPrepareDC so headers and page numbers won't be affected. An alternative approach is to forego the call to OnDraw and do all your printing in OnPrint. If your drawing and printing code are substantially different, doing the printing in OnPrint draws a clearer boundary between how you print a document and how you render it on screen.CView::OnFilePrint and Other Command HandlersPrinting usually begins when the user selects the Print command from the File menu. MFC provides a CView::OnFilePrint that you can connect to the ID_FILE_PRINT menu item through the view's message map. Figure 3 summarizes what happens when the user prints. It also shows how the MFC print architecture meshes with the Windows print architecture because, if you take away the round rectangles representing the virtual CView functions that the framework calls, you're left with a pretty good schematic of the Windows printing model. Note that OnPrepareDC is called twice per page when your code executes under Windows 95. The first call to OnPrepareDC is made to preserve compatibility with 16-bit versions of MFC, which called OnPrepareDC before StartPage (and got away with it because in 16-bit Windows, it's EndPage, not StartPage, that resets the device context). The second call is made because, in Windows 95, changes made to the device context in the first call to OnPrepareDC arenullified when StartDoc is called.Figure 3 Overwiew of the MFC Print ArchitectureMFC also provides predefined command IDs and default command handlers for the File menu's Print Preview and Print Setup commands. The Print Preview command (ID=ID_FILE_PRINT_PREVIEW) is handled by CView::OnFilePrintPreview, and Print Setup (ID=ID_FILE_PRINT_SETUP) is handled by CWinApp::OnFilePrintSetup. Like OnFilePrint, these command handlers are not prewired into the message maps of the classes to which they belong. To enable them, you must do the message mapping yourself. Of course, if you use AppWizard to generate the skeleton of an application that prints, the message mapping is done for you. AppWizard also maps ID_FILE_PRINT_DIRECT to CView::OnFilePrint to enable "direct" printing—printing performed not by selecting Print from the Filemenu, but by dropping a document icon onto a printer.Print PreviewOnce a document/view application can print, adding print preview is as simple as adding a Print Preview command and hooking it up to CView::OnFilePrintPreview. There's a lot of code in the class library to support OnFilePrintPreview (see Viewprev.cpp for details), but what happens is pretty simple.OnFilePrintPreview takes over the frame window and fills it with a view created from a special CScrollView-derived class named CPreviewView. It adds a toolbar with buttons for going to the next or previous page, switching between one-page and two-page views, zooming in and out, and so on.CPreviewView::OnDraw draws a white rectangle representing a printed page (or two rectangles if。
MFC打印和打印预览MFC提供了一个框架性的打印和打印预览功能代码,它的基本思想是将实际显示和打印文档的代码合二为一,即都由此文档关联的CView中的OnDraw(CDC *pDC)来处理,由MFC框架根据用户的操作来决定传进来的pDC是指向屏幕还是打印机,当pDC指向屏幕设备,就在屏幕上显示文档,当指向打印机设备时就打印文档。
这些都很好理解,但是,当我们要打印预览时,传进来的pDC就有些特别了。
因为打印预览是在屏幕上进行的,所以通常我们会认为这时传进来的pDC一定也是属于屏幕DC一类的。
但是其实不然,这个pDC是根据当前默认的打印机的属性来构造的。
举个例子,我的计算机上安装了一个打印机,它的默认打印纸是A4大小(210mm X 297mm),而它的默认分辨率是1200dpi。
当打印预览时Cview::OnDraw函数中的pDC指向的就是那个用来预览输出的DC,现在我们调用pDC->GetDeviceCaps(HORZSIZE),pDC->GetDeviceCaps(VERTSIZE),这两个函数用来取得DC显示区域的大小,以毫米为单位,得到的返回值为210和297,这恰好就是A4纸的大小。
接着再调用pDC->GetDeviceCaps(HORZRES),pDC->GetDeviceCaps(VERTRES),这两个调用返回的也是DC显示区域的大小,不过单位是象素(或者说是点dot),得到的值是9917和14031。
让我们看看这两个值与上面的210和297有什么关系。
1英寸等于25.4毫米,那么210毫米的长度按照1200dpi的分辨率能容纳多少点?当然是210/25.4×1200,算算看等于多少?没错,就是9917左右(实际是9921.259……),同样可以将297换算成14031。
现在来看看另外一个问题。
当我们用MemDC.CreateCompatibleDC(pDC)来创建一个与pDC兼容的内存DC时,调用GetDeviceCaps(HORZSIZE)等函数得到的值是否与pDC的一样呢?答案是不一样。
基于MFC对话框的报表打印和预览功能第一步:在工程中加入实现打印功能的四个文件PrintFrame.h,PringtView.h,PrintFrame.cpp, PrintView.cppCPrintFrame和CPrintView类是两个个可重用的类,开发者只需要把这两个类对应的四个文件拷贝到工程文件所在目录中(PrintFrame.h,PringtView.h,PrintFrame.cpp, PrintView.cpp),并将这四个文件加入工程,并在需要执行打印功能的代码处加入#include "PrintFrame.h"#include "PrintView.h"第二步:添加三个消息响应函数来执行该功能ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting)ON_MESSAGE(WM_END_PRINTING,OnEndPrinting)ON_MESSAGE(WM_MY_PRINT,OnMyPrint)这三个消息响应函数放在.cpp文件的BEGIN_MESSAGE_MAP(CReportDlg, CDialog)与END_MESSAGE_MAP()之间,如下:BEGIN_MESSAGE_MAP(CReportDlg, CDialog) //{{AFX_MSG_MAP(CReportDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON1, OnButton1)ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting)ON_MESSAGE(WM_END_PRINTING,OnEndPrinting)ON_MESSAGE(WM_MY_PRINT,OnMyPrint)ON_BN_CLICKED(IDC_BUTTON2, OnButton2)//}}AFX_MSG_MAPEND_MESSAGE_MAP()其中OnMyPrint是跟具体要打印什么内容有关的开发人员要重点完成的代码,可以打印表格,图片,数据,只要GDI绘图可以进行的操作在这里都可以完成。
winform打印和预览 在windows应⽤程序中⽂档的打印是⼀项⾮常重要的功能,在以前⼀直是⼀个⾮常复杂的⼯作,Microsoft .Net Framework的打印功能都以组件的⽅式提供,为程序员提供了很⼤的⽅便。
由于⼯作中常⽤到印功功能,个⼈写了⼀个专门打印DataGridView对象⼀个类,可以实现预览和打印功能,⽽且⾃动缩放字段、添加颜⾊;在预览时可以根据不同的⽐例查看效果,可以查看第⼏页数据和直接打印第⼏页的数据。
请看效果图。
⼆、附上调⽤代码三、提供源码:1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.Drawing.Printing;6using System.Windows.Forms;7using System.Drawing;8using ponent;9namespace Bll10 {11///<summary>12///打印13///开⼼懒⼈14/// 2014-10-1015///</summary>16public class PrintDataGridView17 {1819static DataGridView dgv;20static string titleName = ""; //标题名称21static string titleName2 = ""; //第⼆标题名称22static int rowIndex = 0; //当前⾏23static int page = 1; //当前页24static int rowsPerPage = 0; //每页显⽰多少⾏25///<summary>26///打印DataGridView27///</summary>28///<param name="dataGridView">要打印的DataGridView</param>29///<param name="title">标题</param>30///<param name="title2">第⼆标题,可以为null</param>31public static void Print(DataGridView dataGridView, string title, string title2)32 {33try34 {35if (dataGridView == null) { return; }36 titleName = title;37 titleName2 = title2;38 dgv = dataGridView;39 PrintPreviewDialog ppvw = new PrintPreviewDialog();40 ppvw.PrintPreviewControl.Zoom = 1.0; //显⽰⽐例为100%41 PrintDocument printDoc = new PrintDocument();42 PrintDialog MyDlg = new PrintDialog();43 MyDlg.Document = printDoc;44 printDoc.DefaultPageSettings.PaperSize = new PaperSize("A4", 850, 1000);45 printDoc.DefaultPageSettings.Margins = new Margins(60, 60, 60, 60); //设置边距46 ppvw.Document = printDoc; //设置要打印的⽂档47 ((Form)ppvw).WindowState = FormWindowState.Maximized; //最⼤化48 rowIndex = 0; //当前⾏49 page = 1; //当前页50 printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage); //打印事件51 printDoc.EndPrint += new PrintEventHandler(printDoc_EndPrint);52 ndscape = true; // 设置打印为横向53 ppvw.ShowDialog(); //打开预览5455 }56catch (Exception ex)57 {58 MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);59 }6061 }6263static void printDoc_EndPrint(object sender, PrintEventArgs e)64 {65 rowIndex = 0; //当前⾏66 page = 1; //当前页67 rowsPerPage = 0;//每页显⽰多少⾏68 }69private static void printDoc_PrintPage(object sender, PrintPageEventArgs e)70 {7172//标题字体73 Font titleFont = new Font("微软雅⿊", 16, FontStyle.Bold);74//标题尺⼨75 SizeF titleSize = e.Graphics.MeasureString(titleName, titleFont, e.MarginBounds.Width);76//x坐标77int x = e.MarginBounds.Left;78//y坐标79int y = Convert.ToInt32(e.MarginBounds.Top - titleSize.Height);80//边距以内纸张宽度81int pagerWidth = e.MarginBounds.Width;82//画标题83 e.Graphics.DrawString(titleName, titleFont, Brushes.Black, x + (pagerWidth - titleSize.Width) / 2, y);84 y += (int)titleSize.Height;85if (titleName2 != null && titleName2 != "")86 {8788//画第⼆标题89 e.Graphics.DrawString(titleName2, dgv.Font, Brushes.Black, x + (pagerWidth - titleSize.Width) / 2 + 200, y);90//第⼆标题尺⼨91 SizeF titleSize2 = e.Graphics.MeasureString(titleName2, dgv.Font, e.MarginBounds.Width);92 y += (int)titleSize2.Height;9394 }9596//表头⾼度97int headerHeight = 0;98//纵轴上内容与线的距离99int padding = 6;100//所有显⽰列的宽度101int columnsWidth = 0;102//计算所有显⽰列的宽度103foreach (DataGridViewColumn column in dgv.Columns)104 {105106//隐藏列返回107if (!column.Visible) continue;108//所有显⽰列的宽度109 columnsWidth += column.Width;110 }111112//计算表头⾼度113foreach (DataGridViewColumn column in dgv.Columns)114 {115116//列宽117int columnWidth = (int)(Math.Floor((double)column.Width / (double)columnsWidth * (double)pagerWidth));118//表头⾼度119int temp = (int)e.Graphics.MeasureString(column.HeaderText, column.InheritedStyle.Font, columnWidth).Height + 2 * padding;120if (temp > headerHeight) headerHeight = temp;121 }122123//画表头124125foreach (DataGridViewColumn column in dgv.Columns)126 {127128//隐藏列返回129if (!column.Visible) continue;130//列宽131int columnWidth = (int)(Math.Floor((double)column.Width / (double)columnsWidth * (double)pagerWidth));132//内容居中要加的宽度133float cenderWidth = (columnWidth - e.Graphics.MeasureString(column.HeaderText, column.InheritedStyle.Font, columnWidth).Width) / 2;134if (cenderWidth < 0) cenderWidth = 0;135//内容居中要加的⾼度136float cenderHeight = (headerHeight + padding - e.Graphics.MeasureString(column.HeaderText, column.InheritedStyle.Font, columnWidth).Height) / 2; 137if (cenderHeight < 0) cenderHeight = 0;138//画背景139 e.Graphics.FillRectangle(new SolidBrush(Color.LightGray), new Rectangle(x, y, columnWidth, headerHeight));140//画边框141 e.Graphics.DrawRectangle(Pens.Black, new Rectangle(x, y, columnWidth, headerHeight));142////画上边线143144//e.Graphics.DrawLine(Pens.Black, x, y, x + columnWidth, y);145146////画下边线147148//e.Graphics.DrawLine(Pens.Black, x, y + headerHeight, x + columnWidth, y + headerHeight);149150////画右边线151152//e.Graphics.DrawLine(Pens.Black, x + columnWidth, y, x + columnWidth, y + headerHeight);153154//if (x == e.MarginBounds.Left)155156//{157158////画左边线159160// e.Graphics.DrawLine(Pens.Black, x, y, x, y + headerHeight);161162//}163164//画内容165 e.Graphics.DrawString(column.HeaderText, column.InheritedStyle.Font, new SolidBrush(column.InheritedStyle.ForeColor), new RectangleF(x + cenderWidth, y + cenderHeight, columnWidth, headerHeight)); 166 x += columnWidth;167168 }169170 x = e.MarginBounds.Left;171 y += headerHeight;172while (rowIndex < dgv.Rows.Count)173 {174175 DataGridViewRow row = dgv.Rows[rowIndex];176if (row.Visible)177 {178179int rowHeight = 0;180foreach (DataGridViewCell cell in row.Cells)181 {182183 DataGridViewColumn column = dgv.Columns[cell.ColumnIndex];184if (!column.Visible || cell.Value == null) continue;185int tmpWidth = (int)(Math.Floor((double)column.Width / (double)columnsWidth * (double)pagerWidth));186int temp = (int)e.Graphics.MeasureString(cell.Value.ToString(), column.InheritedStyle.Font, tmpWidth).Height + 2 * padding;187if (temp > rowHeight) rowHeight = temp;188 }189190foreach (DataGridViewCell cell in row.Cells)191 {192193 DataGridViewColumn column = dgv.Columns[cell.ColumnIndex];194if (!column.Visible) continue;195int columnWidth = (int)(Math.Floor((double)column.Width / (double)columnsWidth * (double)pagerWidth));196 e.Graphics.DrawRectangle(Pens.Black, new Rectangle(x, y, columnWidth, rowHeight));197198if (cell.Value != null)199 {200201//内容居中要加的宽度202203float cenderWidth = (columnWidth - e.Graphics.MeasureString(cell.Value.ToString(), cell.InheritedStyle.Font, columnWidth).Width) / 2;204205if (cenderWidth < 0) cenderWidth = 0;206207//内容居中要加的⾼度208209float cenderHeight = (rowHeight + padding - e.Graphics.MeasureString(cell.Value.ToString(), cell.InheritedStyle.Font, columnWidth).Height) / 2;210211if (cenderHeight < 0) cenderHeight = 0;212213////画下边线214215//e.Graphics.DrawLine(Pens.Black, x, y + rowHeight, x + columnWidth, y + rowHeight);216217////画右边线218219//e.Graphics.DrawLine(Pens.Black, x + columnWidth, y, x + columnWidth, y + rowHeight);220221//if (x == e.MarginBounds.Left)222223//{224225////画左边线226227// e.Graphics.DrawLine(Pens.Black, x, y, x, y + rowHeight);228229//}230231//画内容232233 e.Graphics.DrawString(cell.Value.ToString(), column.InheritedStyle.Font, new SolidBrush(cell.InheritedStyle.ForeColor), new RectangleF(x + cenderWidth, y + cenderHeight, columnWidth, rowHeight)); 234235 }236237 x += columnWidth;238239 }240241 x = e.MarginBounds.Left;242243 y += rowHeight;244245if (page == 1) rowsPerPage++;246247//打印下⼀页248249if (y + rowHeight > e.MarginBounds.Bottom)250 {251252 e.HasMorePages = true;253254break;255256 }257258 }259260 rowIndex++;261262 }263264//页脚265string footer = " 第 " + page + " 页,共 " + Math.Ceiling(((double)dgv.Rows.Count / rowsPerPage)).ToString() + " 页";266//画页脚267 e.Graphics.DrawString(footer, dgv.Font, Brushes.Black, x + (pagerWidth - e.Graphics.MeasureString(footer, dgv.Font).Width) / 2, e.MarginBounds.Bottom); 268 page++;269270 }271272273 }274275 }View Code。
微软Word具有很强大的文档编辑、排版能力,使用它我们可以很方便地编写优秀的文案,或是写出不朽的文学巨著,抑或做出各式各样精美的统计报表等。
显而易见,世界上绝大多数公司或机构直接受益于Word自动化办公。
真不敢想象,没有word的世界会是怎样的。
在实际工作中,面对巨大的业务数据,我们总是希望有那么一个软件来帮我们分析数据,最后生成标准格式的word报表,供我们直接使用。
一切是多么地惬意。
笔者毕业设计所编的软件就需要有报表输出功能,以前曾用VB的水晶报表实现过通讯录打印,但惧于对VB年久生疏及水晶报表的繁杂,还是想到了调用word自动生成报表。
Baidu了一下,发现先行者不少,按他们的经验,磕磕绊绊,终于在VC2005 + OFFICE XP环境下实现了MFC调用WORD进行报表制作。
值得高兴的是,经过努力,实现了插入图片和自动执行宏,这使制作有个性的报表成为可能,比如自动生成页眉,自动加入页码,自动生成目录等。
下面就介绍如何在VC2005中调用WORD制作报表。
首先, 引入类型库。
方法“工程->添加类->选择MFC类从类型库导入”,选择”Microsoft Word 10.0 Obje ct Library <8.2>”, 导入所有接口。
点击完成后,工程目录下会引入相应的头文件。
这些头文件实现了Word 相关接口。
但是并不是所有接口我们都用得到,所以实际使用时候,只包含我们感兴趣的项就可以。
把所有自动引入的头文件,移动到新建文件夹Report里,以后的项目如果需要调用报表,引入该文件夹即可。
不需要重新导入库。
需要注意的是,由于函数命名冲突,需要在生成的头文件做相应处理。
即:#import "C:\\Program Files\\Microsoft Office\\Office10\\MSWORD.OLB" no_namespace \ raw_interfaces_only\rename("FindText", "_FindText") \rename("Rectangle", "_Rectangle") \rename("ExitWindows", "_ExitWindows")如果你使用的是其他版本的Word,那么可以根据下表修改MSWORD.OLB库路径。
MFC应用程序框架打印预览功能分析与扩展
佚名
【期刊名称】《电脑编程技巧与维护》
【年(卷),期】2000(000)009
【摘要】本文针对MFC应用程序框架实现的打印预览功能进行了分析,详细阐述了打印预览功能的实现过程,并在此基础上给出了一种对其进行扩展的方法。
【总页数】4页(P14-17)
【正文语种】中文
【中图分类】TP316.7
【相关文献】
1.MFC应用程序框架的基本特性 [J], 吴敏
2.MFC应用程序框架封装技术在Matlab/Simulink中的应用 [J], 吴成富;张开宝;马松辉
3.MFC应用程序框架的再认识 [J], 韩光宇
4.用MFC编程实现较大视图的打印预览 [J], 韩传武
5.Visual C++5.0MFC编程中的文档打印及打印预览技术 [J], 陈文颂
因版权原因,仅展示原文概要,查看原文内容请购买。
MFC对话框使用CPrintDialog实现打印,指定打印机、后台打印对话框打印,网上一搜一大堆,基本分2类:A类:CPrintDialog.DoModal,然后在模态对话框里选打印机、打印配置;B类:GetPrinterDeviceDefaults,调用默认打印机。
我的工作内容是理解以上2类后,再根据MSDN,实现MDF对话框后台指定打印机打印。
废话不多说,上菜~功能:基于对话框的MFC打印(非文档视图结构),指定打印机,后台打印(不弹出对话框)思路:1、枚举打印机,并选择其中一个;2、CPrintDialog实例指定到选中的打印机;3、CPrintDialog后台打印具体实现:1、变量(控件)。
在对话框上添加一个combobox (IDC_COMBO1,对应变量m_cboPrint)、一个edit (IDC_EDIT1),edit允许回车,多行(代码就不贴了,知道MFC应该就懂);2、在OnInitDialog里枚举打印机设备,如果报函数未定义,加入头文件#include <winspool.h>需要调用两次EnumPrinters函数,第一次的到结构体的大小,第二次得到打印机列表// TODO: 在此添加额外的初始化代码DWORD dwNeeded;DWORD dwReturn;DWORD dwFlag = PRINTER_ENUM_CONNECTIONS | PRINTER_ENUM_LOCAL;EnumPrinters(dwFlag, NULL, 4, NULL, 0, &dwNeeded, &dwReturn);PRINTER_INFO_4* p4;p4 = new PRINTER_INFO_4[dwNeeded];EnumPrinters(dwFlag, NULL, 4, (PBYTE)p4, dwNeeded, &dwNeeded, &dwReturn);for (int i = 0; i<(int)dwReturn; i++)this->m_cboPrint.AddString(p4[i].pPrinterName);delete []p4;3、操作对话框,在IDC_EDIT1里输入打印的内容,在IDC_COMBO1里选中打印机;4、打印(我是用OK按钮打印的,大家随便)// TODO: 在此添加控件通知处理程序代码// CDialogEx::OnOK();this->UpdateData();CString strMessage;CString strPrintDevice;this->GetDlgItem(IDC_EDIT1)->GetWindowT extW(strMessa ge);strMessage += _T("\r\n"); //添加结尾,方便后面循环读取打印数据this->GetDlgItem(IDC_COMBO1)->GetWindowTextW(strPri ntDevice);DWORD dwFlag = PD_ALLPAGES | PD_NOPAGENUMS | PD_USEDEVMODECOPIES | PD_HIDEPRINTTOFILE; //打印配置界面的按钮可用性,因为后台打印,其实这个配置没什么意义CPrintDialog pPrintdlg(FALSE, dwFlag, this);//CPrintDialog实例化,因为MFC的打印设备无关性,可以理解为这就是一台打印机HGLOBAL hDevMode = NULL;HGLOBAL hDevNames = NULL;if (GetPrinterDevice(strPrintDevice.GetBuffer(0), &hDevNames, &hDevMode)) //获得指定打印机的配置、名字AfxGetApp()->SelectPrinter(hDevNames, hDevMode);elseAfxMessageBox(_T("Failed to select custom printer"));strPrintDevice.ReleaseBuffer();pPrintdlg.m_pd.hDevMode = hDevMode;//让pPrintdlg使用我们指定的打印机pPrintdlg.m_pd.hDevNames = hDevNames;CDC dc;dc.Attach(pPrintdlg.CreatePrinterDC());//后台打印创建法,如果需要弹出打印对话框,请用DoModalDOCINFO di;//下面的内容网上很多,就不解释了di.cbSize = sizeof(DOCINFO);di.lpszDocName = _T("有驱打印测试");di.lpszDatatype = NULL;di.lpszOutput = NULL;di.fwType = 0;dc.StartDocW(&di);dc.StartPage();dc.SetMapMode(MM_TEXT);CRect recPrint(0, 0, dc.GetDeviceCaps(LOGPIXELSX), dc.GetDeviceCaps(LOGPIXELSY));dc.DPtoLP(&recPrint);dc.SetWindowOrg(0, 0);CFont newFont;VERIFY(newFont.CreatePointFont(120, _T("宋体"), &dc));CFont* oldFont = dc.SelectObject(&newFont);dc.SetTextAlign(TA_TOP | TA_LEFT);CString strPrint;int nIndex = 0;int x = 50;int y = 50;CSize textSize;textSize = dc.GetT extExtent(_T("00"), 2);//根据当前字体的宽、高,后面以此高度为行高while ((nIndex = strMessage.Find(_T("\r\n"))) > -1)//将IDC_EDIT1编辑框中内容打印,支持换行,一次换行等于'\r\n',所以在开头strMessage += _T("\r\n") {strPrint = strMessage.Left(nIndex);strMessage = strMessage.Mid(nIndex+2);dc.TextOutW(x, y, strPrint);y += textSize.cy;//下移一行,行高为字体高度}dc.SelectObject(oldFont);newFont.DeleteObject();dc.EndPage();dc.EndDoc();DeleteDC(dc.Detach());关于GetPrinterDevice,来自微软的一篇文章,点我跳转代码也贴出来BOOL CMFCApplication2Dlg::GetPrinterDevice(LPTSTR pszPrinterName, HGLOBAL* phDevNames, HGLOBAL* phDevMode){// if NULL is passed, then assume we are setting app object's// devmode and devnamesif (phDevMode == NULL || phDevNames == NULL)return FALSE;// Open printerHANDLE hPrinter;if (OpenPrinter(pszPrinterName, &hPrinter, NULL) == FALSE) return FALSE;// obtain PRINTER_INFO_2 structure and close printerDWORD dwBytesReturned, dwBytesNeeded;GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded);PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)GlobalAlloc(GPTR, dwBytesNeeded);if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,&dwBytesReturned) == 0) {GlobalFree(p2);ClosePrinter(hPrinter);return FALSE;}ClosePrinter(hPrinter);// Allocate a global handle for DEVMODEHGLOBAL hDevMode = GlobalAlloc(GHND, sizeof(*p2->pDevMode) +p2->pDevMode->dmDriverExtra);ASSERT(hDevMode);DEVMODE* pDevMode = (DEVMODE*)GlobalLock(hDevMode);ASSERT(pDevMode);// copy DEVMODE data from PRINTER_INFO_2::pDevMode memcpy(pDevMode, p2->pDevMode, sizeof(*p2->pDevMode) +p2->pDevMode->dmDriverExtra);GlobalUnlock(hDevMode);// Compute size of DEVNAMES structure from PRINTER_INFO_2's dataDWORD drvNameLen = lstrlen(p2->pDriverName)+1; // driver nameDWORD ptrNameLen = lstrlen(p2->pPrinterName)+1; // printer nameDWORD porNameLen = lstrlen(p2->pPortName)+1; // port name// Allocate a global handle big enough to hold DEVNAMES.HGLOBAL hDevNames = GlobalAlloc(GHND,sizeof(DEVNAMES) +(drvNameLen + ptrNameLen + porNameLen)*sizeof(TCHAR));ASSERT(hDevNames);DEVNAMES* pDevNames = (DEVNAMES*)GlobalLock(hDevNames);ASSERT(pDevNames);// Copy the DEVNAMES information from PRINTER_INFO_2 // tcOffset = TCHAR Offset into structureint tcOffset = sizeof(DEVNAMES)/sizeof(TCHAR);ASSERT(sizeof(DEVNAMES) == tcOffset*sizeof(TCHAR));pDevNames->wDriverOffset = tcOffset;memcpy((LPTSTR)pDevNames + tcOffset, p2->pDriverName, drvNameLen*sizeof(TCHAR));tcOffset += drvNameLen;pDevNames->wDeviceOffset = tcOffset;memcpy((LPTSTR)pDevNames + tcOffset, p2->pPrinterName,ptrNameLen*sizeof(TCHAR));tcOffset += ptrNameLen;pDevNames->wOutputOffset = tcOffset;memcpy((LPTSTR)pDevNames + tcOffset, p2->pPortName, porNameLen*sizeof(TCHAR));pDevNames->wDefault = 0;GlobalUnlock(hDevNames);GlobalFree(p2); // free PRINTER_INFO_2// set the new hDevMode and hDevNames*phDevMode = hDevMode;*phDevNames = hDevNames;return TRUE;}基本上是完整代码了,如果有内存错误,请联系我。
: :首页 >> 文档中心 >> 在线杂志 >> 报表与打印[ 原创文档本文适合中级读者已阅读 1 6 1 8 0次 ]使用 MFC 编写打印程序作者:戎亚新南京航空航天大学仿真与控制实验室下载源代码摘要[ 在线杂志第47 期 ]文档本文首先介绍了利用MFC提供的文档视图框架来实现一个打印程序,实现打印预览,在此基础上,同时通过对MFC源代码的深入探讨,提出了利用该方法在对话框上用MFC实现打印功能,结果表明,利用MFC实现打印不仅方便,而且功能很强大,能够根据不同的需求很方便的打印出所需要的格式。
本文还实现了一个在对话框中利用MFC 实现打印功能的一个框架结构,对于使用者只要使用该结构就可以按照自己的要求打印任何内容。
关键词:Visual C+ + ,MFC,对话框,打印,打印预览引言打印程序的编写在windows程序设计中非常有用,针对不同的用户需要,通常用sdk方式实现打印代码量比较大,而且要对打印流程的底层有非常清楚的了解,需要一个程序员有非常深入的打印方面的知识,利用MFC提供的文档视图结构,不但可以实现一些常用的标准界面元素,把数据的处理的界面的处理分离出来,而且其提供的打印功能更是方便快捷,功能强大。
打印程序的编写本质是是一种GDI绘图,只是绘图的对象是在打印机的设备描述表,如果对于屏幕的GDI绘图比较熟悉的读者,相信掌握打印程序的编写应该比较容易。
1、文档视图结构的程序的打印程序的编写通常情况下,一个结构组织的比较好的MFC程序是基于文档视图结构的,这一框架结构给我们提供了很多功能,比如菜单,注册表的关联,文件类型的注册,打印功能,只要我们善于发掘,这些都可以为我们所用,但我们现在只关心如何使用MFC提供的结构来实现打印功能。
在编写打印程序之前,有必要先介绍一下MFC的框架结构,其中的文档视图结构又是这个框架的重点,我们通过分析MFC实现的视图类的原代码就可以看到一个打印程序的执行流程。
MFC对excel的操作VC操作Excel1、Excel的层次结构:ApplicationWorkbooksWorkbook......WorksheetsWorksheet......RangeFontBorders.............2、插入类型库(1)、在一个已有的MFC工程按Ctrl + W 弹出ClassWizard对话框。
(2)、Add Class...\From a type Library... 在Office 目录中,找到你想使用的Excel类型库(Offce2000下,此目录在C:\Program Files\Microsoft Office\Office\EXCEL9.OLB;Offce2003下,此目录在C:\Program Files\Microsoft Office\OFFICE11\EXCEL.EXE)。
选择EXCEL9.OLB 或EXCEL.EXE;(3)、在弹出的对话框中选择要添加的类,具体选那些类要根据实际情况而定。
当然你也可以全选3、基本操作当你要选用Excel生成报表时,表的结构可能有固定的部分,这时做一个模板,这样可以减少编码的负担。
加载Excel模板的代码如下://(1)定义变量:下面的类型都是通过加入EXCEL类型库之后自动定义的C++类,你可以自由使用。
(_Application,Workbook……等)_Application ExcelApp; // 定义Excel应用程序Workbooks wbsBooks;_Workbook wbBook;Worksheets wssSheets;_Worksheet wsSheet;Range rngXls;FontXls font; // 字体BordersXls border; // 边框//(2)初始化Com,一般放在应用程序类的初始化函数中,并在结束时使用::CoUninitialize();释放COM库。
基于MFC的单⽂档,多⽂档,对话框应⽤程序基于对话框(3个类):CAboutDlg程序名App程序名Dlg单⽂档(5个类):CAboutDlgCMainFrame程序名App程序名Doc程序名View多⽂档(6个类):CAboutDlgCMainFrame程序名App程序名Doc程序名ViewCChildFrame多⽂档CAboutDlg(“关于”对话框) CAboutDlg() DoDataExchange(CDataExchange* pDX)CChildFrame(⼦框架类) AssertValid() CChildFrame() ~CChildFrame() Dump(CDumpContext& dc) PreCreateWindow(CREATESTRUCT& cs)CMainFrame(主框架类) AssertValid() CMainFrame() ~CMainFrame() Dump(CDumpContext& dc) OnCreate(LPCREATESTRUCT lpCreateStruct) PreCreateWindow(CREATESTRUCT& cs) CStatusBar m_wndStatusBar; CToolBar m_wndToolBar;CMyApp(应⽤程序类) CMyApp() InitInstance() OnAppAbout()CMyDoc(⽂档类) AssertValid() CMyDoc() Serialize(CArchive& ar)CMyView(视图类) AssertValid() CMyView() ~CMyView() Dump(CDumpContext& dc) GetDocument() OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) OnDraw(CDC* pDC) OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) OnPreparePrinting(CPrintInfo* pInfo) PreCreateWindow(CREATESTRUCT& cs)Golbals(全局) theApp -------------------------------------------------------------------------------单⽂档CAboutDlg(“关于”对话框) CAboutDlg() DoDataExchange(CDataExchange* pDX)CMainFrame(主框架类) AssertValid() CMainFrame() ~CMainFrame() Dump(CDumpContext& dc) OnCreate(LPCREATESTRUCT lpCreateStruct) PreCreateWindow(CREATESTRUCT& cs) CStatusBar m_wndStatusBar; CToolBar m_wndToolBar;CMyApp(应⽤程序类) CMyApp() InitInstance() OnAppAbout()CMyDoc(⽂档类) AssertValid() CMyDoc() Serialize(CArchive& ar)CMyView(视图类) AssertValid() CMyView() ~CMyView() Dump(CDumpContext& dc) GetDocument() OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) OnDraw(CDC* pDC) OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) OnPreparePrinting(CPrintInfo* pInfo) PreCreateWindow(CREATESTRUCT& cs)Golbals(全局) theApp-------------------------------------------------------------------------------对话框CAboutDlg(“关于”对话框) CAboutDlg() DoDataExchange(CDataExchange* pDX)CMyApp(应⽤程序类) CMyApp() InitInstance()CMyDlg(对话框类) CMyDlg(CWnd* pParent /*=NULL*/) DoDataExchange(CDataExchange* pDX) OnInitDialog() OnPaint() OnQueryDragIcon() OnSysCommand(UINT nID, LPARAM lParam) HICON m_hIcon;Golbals(全局) theAppCXXXApp是应⽤程序类,负责程序的启动和结束CXXXDlg是主对话框类,程序的主界⾯。
MFC/VC++调用word进行报表制作使用word进行数据报告的制作可谓非常方便,word具有非常强大的编辑、排版功能。
使用word能够制作出内容丰富、样式精美的报告。
我们在工作中当然会有报表报告的需求,如果能够在MFC/VC++里面能够调用word进行word格式报告的自动生成,岂不是一件非常惬意的事情。
我在工作当中需要对大量的数据或者各种测试数据进行统计分析,最终的统计分析结果总归要汇总为一份报告,不管是内部使用也好还是外部提供给客户也好,一份内容翔实、格式精美的报告自然必不可少。
我对MFC/VC++也不是高手,只是业余爱好自己动动手做些东西。
自然,低于VC操作word可谓完全没有经验,在网络上面也查找了很多资料,都是些只言片语,不能真正的领略通过VC使用word的方法。
于是自己摸索了几个礼拜,可谓耗时甚长,劳心劳力啊。
MS的东西,封装的也太严实了,对于函数部分只有些许的简单介绍,往往看的云里雾里。
没有实践还是不行啊!体会自己的经历,虽然辛苦但也有收获。
不想其他朋友再继续走我走过的路,浪费时间、精力,故成文以共享。
废话少说,进入正题吧。
第一步,当然我们需要首先导入word需要的库。
通过ClassWizard->Add C lass选择From a Type Library…定位需要的库文件导入。
本例应该使用C:\Pr ogram Files\Microsoft Office\OFFICE11\MSWORD.OLB,在这里尽可选择所有的类导入,反正用的时候都有了,呵呵。
完成这一步,我们得到两个文件ms word.h和msword.cpp,那就加入你的工程吧。
说明:如果需要在VC++/MFC开发程序操作word/excel等office元素,那么需要对必要的类型库进行导入.下面是office系列的类型库参考,导入类型库时候请选择注意:这些类型库的默认位置是:Dao350.dll 和Dao360.dll 的默认位置是C:\Program Files\Common File s\Microsoft Shared\Dao。
C#winform打印excel的⽅法前⾔c#做winform程序要求⽣成并打印Excel报告,为了不安装Office相应组件,我选择了NPOI来⽣成Excel报告,⽤winform的PrintDocument控件来触发打印操作,⽽难点在于如何将excel转换成Graphics对象,在NPOI中我只找到了excel打印的设置(如横向/纵向),还需要打开excel去触发打印操作,但项⽬要求是⼀次性直接实现打印,要⽤PrintDocument控件⽽不是再去操作excel。
不得已重新搜索,发现了类库Spire.xls,最终实现了要求。
有什么错误或更简洁的⽅法还请⼴⼤博友不吝赐教。
思路⽤npoi⽣成Excel =》⽤spire.xls转换成图⽚.png =》获取⽣成的图⽚,利⽤Graphic的drawimage⽅法对图⽚进⾏操作,当然了,如果不介意的话,可以不对图⽚进⾏操作:) =》使⽤printDocument控件的print⽅法实现打印( 当然这⾥可以直接⽤spire.xls直接⽣成Excel,但是Spire.xls的免费版本有每个sheet最多有150⾏的限制 )知识点【0】NPOI使⽤⽅法【1】winform的printDocument控件理解:PrintDocument控件的作⽤是定义⼀个向打印机发送输出的对象,有BeginPrint,PrintPage,EndPrint⽅法,当执⾏printdocument.Print()语句时,会检查是否存在BeginPrint⽅法,存在则先调⽤。
然后调⽤PrintPage⽅法,该⽅法会向PrintPageEcentArgs类中获得⼀个空⽩的Graphics对象,我们可以对Graphics对象进⾏操作(可以理解对画布进⾏绘制,Graphics对象有内置的类似DrawString,DrawPie的⽅法),在PrintPage⽅法的最后,会向打印设备发送这个Graphics 对象。
MFC与打印打印程序的编写在windows程序设计中非常有用,利用MFC提供的文档视图结构,不但可以实现一些常用的标准界面元素,把数据的处理的界面的处理分离出来,而且其提供的打印功能更是方便快捷,功能强大。
打印程序的编写本质是是一种GDI绘图,只是绘图的对象是在打印机的设备描述表,如果对于屏幕的GDI绘图比较熟悉的读者,相信掌握打印程序的编写应该比较容易。
1、文档视图结构的程序的打印程序的编写使用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 infoif (OnPreparePrinting(&printInfo)){if (dlg.DoModal() != IDOK)return;}OnBeginPrinting(&dcPrint, &printInfo);OnPrepareDC(&dcPrint, &printInfo);OnPrint(&dcPrint, &printInfo);OnEndPrinting(&dcPrint, &printInfo); // clean up after printing}其中加粗的代码行为可以重载的虚函数,根据不同的用户,其内容会不同。
基于MFC对话框的报表打印和预览功能第一步:在工程中加入实现打印功能的四个文件PrintFrame.h,PringtView.h,PrintFrame.cpp, PrintView.cppCPrintFrame和CPrintView类是两个个可重用的类,开发者只需要把这两个类对应的四个文件拷贝到工程文件所在目录中(PrintFrame.h,PringtView.h,PrintFrame.cpp, PrintView.cpp),并将这四个文件加入工程,并在需要执行打印功能的代码处加入#include "PrintFrame.h"#include "PrintView.h"第二步:添加三个消息响应函数来执行该功能ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting)ON_MESSAGE(WM_END_PRINTING,OnEndPrinting)ON_MESSAGE(WM_MY_PRINT,OnMyPrint)这三个消息响应函数放在.cpp文件的BEGIN_MESSAGE_MAP(CReportDlg, CDialog)与END_MESSAGE_MAP()之间,如下:BEGIN_MESSAGE_MAP(CReportDlg, CDialog) //{{AFX_MSG_MAP(CReportDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON1, OnButton1)ON_MESSAGE(WM_BEGIN_PRINTING,OnBeginPrinting)ON_MESSAGE(WM_END_PRINTING,OnEndPrinting)ON_MESSAGE(WM_MY_PRINT,OnMyPrint)ON_BN_CLICKED(IDC_BUTTON2, OnButton2)//}}AFX_MSG_MAPEND_MESSAGE_MAP()其中OnMyPrint是跟具体要打印什么内容有关的开发人员要重点完成的代码,可以打印表格,图片,数据,只要GDI绘图可以进行的操作在这里都可以完成。
由于打印预览的一部分工作在CView类里完成,因此在用户程序中只需要相应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();例如:ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview);ON_BN_CLICKED(IDC_PNT, OnPnt);pFrame->m_pCallerDlg->SendMessage(WM_MY_PRINT,(WPARAM) pDC, (LPARAM) pInfo);pFrame->m_pView->OnMyPrintPreview();void CDlgPrintDlg::OnPrint() //执行打印功能{CPrintFrame *pFrame = new CPrintFrame;pFrame->m_pCallerDlg = this;pFrame->Create(NULL,"CurvePrint",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 PrintPreview",WS_OVERLAPPEDWINDOW,CRect(0,0,0,0));pFrame->m_pView->OnMyPrintPreview();}OnBeginPrinting事例LRESULT 类名::OnBeginPrinting(WPARAM wParam, LPARAM lParam){CDC* pDC = (CDC*)wParam;CPrintInfo* pInfo = (CPrintInfo *)lParam;pInfo->m_pPD ->GetDevMode ()->dmOrientation=1 ;pInfo->SetMaxPage (pagecount);//打印的总页数return TRUE;}OnEndPrinting事例LRESULT 类名::OnEndPrinting(WPARAM wParam, LPARAM lParam){CPrintInfo* pInfo = (CPrintInfo *)lParam;pInfo->m_pPD ->GetDevMode ()->dmOrientation=1 ;return TRUE;}OnMyPrint事例//具体要打印的内容CDC* pDC = (CDC*)wParam;CPrintInfo* pInfo = (CPrintInfo *)lParam;PrintPageHeader(pDC,pInfo->m_nCurPage, pInfo);int nPageNumber = pInfo->m_nCurPage;CFont *pOldFont;CFont font;CSize size;TEXTMETRIC tm;font.CreatePointFont (110,"宋体",pDC);pOldFont=pDC->SelectObject (&font);//选择设备pDC->GetTextMetrics (&tm);int m_width=(pDC->GetDeviceCaps (HORZRES)-3*tm.tmHeight );nPosY+=(int)(0.2*tm.tmHeight );pDC->TextOut ((int)(1.5*tm.tmHeight) ,nPosY," EPC号 "); pDC->TextOut ((int)(1.5*tm.tmHeight+m_width/9*1.6) ,nPosY,"充值前余额 ");pDC->TextOut ((int)(1.5*tm.tmHeight) +m_width/9*3,nPosY,"本次充值金额");pDC->TextOut ((int)(1.5*tm.tmHeight) +m_width/9*4,nPosY,"充值时间 ");nPosY+=(int)(1.2*tm.tmHeight) ;int m_height=(pDC->GetDeviceCaps (VERTRES)-1*tm.tmHeight-nPosY )/48; for(int i=0;i<48;i++){int nPosYtemp=nPosY+m_height*i;CString str=m_List.GetItemText ((nPageNumber-1)*48+i,0);str=str.Right (str.GetLength ()-2);pDC->TextOut ((int)(1.5*tm.tmHeight) ,nPosYtemp,str);pDC->TextOut((int)(1.5*tm.tmHeight+m_width/9*1.6),nPosYtemp,m_List.GetItemText ((nPageNumber-1)*48+i,1));pDC->TextOut ((int)(1.5*tm.tmHeight)+m_width/9*3,nPosYtemp,m_List.GetItemText ((nPageNumber-1)*48+i,2));pDC->TextOut ((int)(1.5*tm.tmHeight)+m_width/9*4,nPosYtemp,m_List.GetItemText ((nPageNumber-1)*48+i,3));}pDC->MoveTo ((int)(1*tm.tmHeight) ,nPosY+m_height*48);pDC->LineTo (pDC->GetDeviceCaps(HORZRES)-(int)(1*tm.tmHeight) ,nPosY+m_height*48);CString strpage="";strpage+="第(";CString str;str.Format ("%d",nPageNumber);strpage+=str;strpage+=")页";font.DeleteObject ();font.CreatePointFont (110,"宋体",pDC);pDC->SelectObject (&font);//选择设备pDC->TextOut (pDC->GetDeviceCaps(HORZRES)-6*tm.tmHeight,(int)(nPosY+m_height*48.2),strpage);pDC->SelectObject (pOldFont);pDC->SelectObject(pOldFont);return TRUE;}PrintPageHeader函数void 类名::PrintPageHeader(CDC *pDC, UINT nPageNumber, CPrintInfo*pInfo){AfxMessageBox("222222");CFont *pOldFont;CFont fontHeader;CPen pen;CPen *pOldPen;pen.CreatePen (PS_SOLID,(int)(5*printxs),RGB(0,0,0));pOldPen=pDC->SelectObject (&pen);fontHeader.CreatePointFont (140,"宋体",pDC);pOldFont=(CFont *)(pDC->SelectObject(&fontHeader));TEXTMETRIC tm;pDC->GetTextMetrics (&tm);nPosY=(int)(0.5*tm.tmHeight) ;CSize sz=pDC->GetTextExtent(strworkname);nPosX=(pDC->GetDeviceCaps (HORZRES)-sz.cx )/2;pDC->TextOut (nPosX,nPosY,strworkname);nPosY+=tm.tmHeight ;fontHeader.DeleteObject ();fontHeader.CreatePointFont (110,"宋体",pDC);pDC->SelectObject(&fontHeader);//绘制用户类型nPosX=tm.tmHeight ;nPosY=nPosY+(int)(0.5*tm.tmHeight );pDC->TextOut(nPosX,nPosY,"用户类型:"+usertype);//绘制姓名nPosX=(pDC->GetDeviceCaps (HORZRES)-2*tm.tmHeight )/3; pDC->TextOut(nPosX,nPosY,"姓名:"+Printname);//绘制打印日期nPosX=(pDC->GetDeviceCaps (HORZRES)-2*tm.tmHeight )/3*2; pDC->TextOut(nPosX,nPosY,"打印日期:"+Printdate);nPosY+=(int)(1.2*tm.tmHeight) ;pDC->GetTextMetrics (&tm);pDC->MoveTo ((int)(1*tm.tmHeight) ,nPosY);pDC->LineTo (pDC->GetDeviceCaps(HORZRES)-(int)(1*tm.tmHeight) ,nPosY);//资源释放pDC->SelectObject(pOldFont);pDC->SelectObject (pOldPen);fontHeader.DeleteObject();pen.DeleteObject ();}。