900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > MFC打印及打印预览

MFC打印及打印预览

时间:2021-11-28 13:40:06

相关推荐

MFC打印及打印预览

总结了一下其中的一些用法:

1:用CPrintDialog 可以呼出窗口让用户选择打印机或者采用默认的打印机直接打印。

StartPage…..EndPage 完成一页文档的打印。 如需改变DC设置,需要调用ReSetDC()

多次调用这两个函数,可以实现打印多页

2:TextOut坐标的确定。

TextOut中的坐标是DC中的逻辑坐标。

和实际的物理坐标需要转换。

GetDeviceCpas(); //获取DC中的Device信息。

GetTextMetrics(); //获取字体的信息。 字体高度和本身高度+行距。

3:TextOut中的字体可以设置。

关键代码如下:

CFont myFont;

myFont.CreatePontFont(….);

oldFont = dc.SelectObject();

myFont.DelectObject()';

打印单位的转换

这个的关键是我们要得到显示设备的DPI,即每英寸设备支持的点数。有了DPI我们就可以在我们习惯的单位和设备单位之间转换了,用到的API是GetDeviceCaps(),这个函数功能强大,具体可参考MSDN,在这里我们只用来得到设备DPI。看示例代码:

//某些设备水平和垂直方向的DPI可能不同,所以要分别得到。//得到水平方向的转换比例float getXScale(HDC printDC) //printDC: 打印机DC设备句柄{//得到打印机水平方向的DPIint xDPI = GetDeviceCaps(printDC, LOGPIXELSX);//254.0: 每英寸25.4毫米float xScale = (float)(254.0 / xDPI);return xScale;}//得到垂直方向的转换比例float getYScale(HDC printDC) //printDC: 打印机DC设备句柄{//得到打印机垂直方向的DPIint yDPI = GetDeviceCaps(printDC, LOGPIXELSY);float yScale = (float)(254.0 / yDPI);return yScale;}//厘米转换为设备像素,水平方向double cm2Unit_W(float xScale, double w) //w单位为厘米{return w*100/xScale;}//厘米转换为设备像素,垂直方向double cm2Unit_H(float yScale, double h) //h单位为厘米{return h*100/yScale;}

上面代码中,如果将printDC换为显示器设备DC句柄,即可得到厘米转换为显示器像素单位,打印预览时使用。得到显示器设备句柄可用::GetDC(NULL)得到。

打印基本流程

有了前面的知识,现在我们就可以打印了。Windows打印是有着固定的流程的,流程也比较简单。按照固定的顺序调用打印API即可:StartDoc() -> StartPage() -> 打印具体内容 -> EndPage() -> EndDoc()。如果要打印多页,循环StartPage()至EndPage()即可。

示例代码:

DOCINFO doc; ZeroMemory(&doc,sizeof(doc)); doc.cbSize = sizeof(doc); doc.lpszDocName = (LPCTSTR)"Print Test File";StartDoc(printDC, &doc); //准备打印StartPage(printDC); //开始打印页//在(2.5cm, 2.5cm)处打印文本char* text = "打印测试文本";float xScale = getXScale(printDC);float yScale = getYScale(printDC);double x = cm2Unit_W(xScale, 2.5);double y = cm2Unit_H(yScale, 2.5);//在指定位置打印文本TextOut(printDC, (int)x, (int)y, (LPTSTR)text, strlen(text));EndPage(printDC); //结束打印页EndDoc(printDC); //结束打印

打印字体的设置

很多时候我们希望能控制打印字体,下面的代码可以创建你想要的字体格式:

/* 创建自定义打印字体fontFace:字体名称,如果为NULL,默认采用“宋体”fontHeight:字体高度,单位为厘米isBold:是否加粗isItalic:是否斜体isUnderLine:是否下划线isStrikeOut:是否删除线*/HFONT getFont(LPCTSTR fontFace, double fontHeight, bool isBold, bool isItalic, bool isUnderLine, bool isStrikeOut){int width = 0; //字体宽度由系统决定int weight = FW_NORMAL;DWORD italic = 0;DWORD underLine = 0;DWORD strikeOut = 0;DWORD charSet = DEFAULT_CHARSET;LPCTSTR face = (LPCTSTR)"宋体";float height = cm2Unit_H(fontHeight);if(fontFace != 0){face = fontFace;}if(isBold){weight = FW_BOLD;}if(isItalic){italic = 1;}if(isUnderLine){underLine = 1;}if(isStrikeOut){strikeOut = 1;}HFONT font = CreateFont((int)height, width, 0, 0, weight, italic, underLine, strikeOut, charSet,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, face );return font;}

小结

以上就是我们在实现打印中遇到的常见问题,相信理解了这些,在我们自己的程序中实现打印就不再是什么困难的事情了。

打印协议

为打印多页文档,框架与视图以如下方式交互。首先,框架显示“打印”对话框,为打印机创建设备上下文,并调用

CDC

对象的

StartDoc

成员函数。然后,对于文档中的每一页,框架调用CDC对象的

StartPage

成员函数,指示视图对象打印页,并调用

EndPage

成员函数。如果在开始某个特定页之前必须更改打印机模式,视图将调用

ResetDC

,它将更新含有新的打印机模式信息的 结构。全部文档打印完毕后,框架调用

EndDoc

成员函数。

重写视图类函数

CView

类定义在打印过程中被框架调用的几个成员函数。通过在视图类中重写这些函数,提供框架打印逻辑与视图类打印逻辑之间的连接。下表列出了这些成员函数。

用于打印的 CView 可重写函数

名称

重写原因

OnPreparePrinting

在“打印”对话框中插入值,尤其是文档的长度

OnBeginPrinting

分配字体或其他 GDI 资源

OnPrepareDC

调整给定页的设备上下文属性,或进行打印时分页

OnPrint

打印给定页

OnEndPrinting

解除分配 GDI 资源

也可用其他函数执行打印相关处理,但这些函数是驱动打印过程的函数。

下图阐释了打印过程所涉及的步骤,并显示了在何处调用CView的每个打印成员函数。本文其余部分是对大多数步骤更详细的解释。一文介绍了打印过程的其他部分。

打印循环

分页

框架在

CPrintInfo

结构中存储许多关于打印作业的信息。CPrintInfo中的几个值是关于分页的;这些值如下表所示。

存储在 CPrintInfo 中的页码信息

成员变量或函数名

引用的页码

GetMinPage/SetMinPage

文档的第一页

GetMaxPage/SetMaxPage

文档的最后一页

GetFromPage

要打印的第一页

GetToPage

要打印的最后一页

m_nCurPage

当前正在打印的页

页码从 1 开始,也就是说,第一页的编号为 1,而不是 0。有关上述及其他

CPrintInfo

成员的更多信息,请参见“MFC 参考”。

在打印过程的开始,框架调用视图的

OnPreparePrinting

成员函数,向CPrintInfo结构传递一个指针。“应用程序向导”提供调用CView的另一个成员函数

DoPreparePrinting

OnPreparePrinting实现。DoPreparePrinting是显示“打印”对话框并创建打印机设备上下文的函数。

这时,应用程序并不知道文档的页数。它对文档的第一页和最后一页的页码使用默认值 1 和 0xFFFF。如果您知道文档的页数,在将文档发送到DoPreparePrinting之前,请重写OnPreparePrinting,并为CPrintInfo结构调用

SetMaxPage

。这使您得以指定文档的长度。

接下来DoPreparePrinting显示“打印”对话框。当它返回时,CPrintInfo结构包含用户指定的值。如果用户希望只打印选定页码范围内的文档,他或她可以在“打印”对话框中指定起始页码和终止页码。框架使用

CPrintInfo

GetFromPageGetToPage函数检索这些值。如果用户未指定页码范围,框架将调用GetMinPageGetMaxPage并使用返回的值来打印整个文档。

对于文档中将要打印的每一页,框架调用视图类中的两个成员函数(

OnPrepareDC

OnPrint

),并传递给每个函数两个参数:一个指向

CDC

对象的指针和一个指向CPrintInfo结构的指针。每次当框架调用OnPrepareDCOnPrint时,它都传递CPrintInfo结构的m_nCurPage成员中的不同值。框架通过这种方式通知视图要打印哪些页。

OnPrepareDC

成员函数也可用于屏幕显示。它在绘制之前调整设备上下文。OnPrepareDC在打印中起同样的作用,但有两点不同:首先,CDC对象表示打印机设备上下文而不是屏幕设备上下文;其次,CPrintInfo对象作为第二个参数传递。(当为屏幕显示调用OnPrepareDC时,此参数为NULL。)重写OnPrepareDC以便根据正在打印的页的不同来调整设备上下文。例如,可通过移动视区原点和剪辑区域,确保文档中的适当部分得到打印。

OnPrint

成员函数执行页的实际打印。一文显示了框架是如何用打印机设备上下文调用

OnDraw

来执行打印的。更确切地说,框架用CPrintInfo结构和设备上下文调用OnPrintOnPrint将设备上下文传递给OnDraw。重写OnPrint,执行任何只应在打印而非屏幕显示期间完成的呈现。例如,打印页眉或页脚(有关更多信息,请参见一文)。然后,从OnPrint的重写调用OnDraw来进行屏幕显示和打印的共同呈现。

OnDraw既进行屏幕显示呈现又进行打印呈现的事实意味着您的应用程序是 WYSIWYG(所见即所得)。然而,假设您正在写的不是“所见即所得”应用程序。例如,一个文本编辑器使用粗体作为打印字体,但同时显示控制代码指示屏幕上粗体文本。对于这种情况,应严格使用OnDraw进行屏幕显示。当您重写OnPrint时,用一个对单独绘制函数的调用取代对OnDraw的调用。该函数使用未显示在屏幕上的属性,以文档显示在纸上的方式绘制文档。

打印机页与文档页

提到页码,有时必须得区分打印机页的概念和文档页的概念。从打印机的角度讲,一页是一张纸。但是,一张纸并不一定等于文档中的一页。例如,如果打印一份通讯稿,纸张将要折叠,一张纸可能同时含有文档的第一页和最后一页(它们是并排的)。同样,如果打印一份电子表格,文档根本不是由页组成的。相反,一张纸可能包含第一到第二十行,第六到第十列。

所有

CPrintInfo

结构中的页码都是指打印机页。框架对通过打印机的每一页纸调用一次OnPrepareDCOnPrint。当重写

OnPreparePrinting

函数来指定文档长度时,必须使用打印机页。如果存在一一对应关系(即,一个打印机页等于一个文档页),那么事情就简单了。反之,如果文档页与打印机页并非一一对应,则必须在两者之间进行转换。例如,打印一份电子表格。当重写OnPreparePrinting时,必须计算打印整个电子表格所需的纸张数,并在调用CPrintInfoSetMaxPage成员函数时使用该值。同样,当重写OnPrepareDC时,必须将m_nCurPage转换成会出现在特定纸张上的行和列的范围,然后相应调整视区原点。

打印时分页

有些情况下,您的视图类可能在文档实际打印之前并不会事先知道文档的长度。例如,如果您的应用程序不是“所见即所得”的,那么屏幕上的文档长度并不对应于其打印时的长度。

当您为视图类重写

OnPreparePrinting

时,就会产生这样的问题:无法向

CPrintInfo

结构的SetMaxPage函数传递值,因为您不知道文档的长度。如果用户不使用“打印”对话框指定终止页码,框架就不知该在何时停止打印循环。唯一可以确定何时停止打印循环的方法是打印出全部文档并弄清其何时终止。您的视图类必须在文档打印期间检查是否到达文档末尾,并在到达时通知框架。

框架依赖于您的视图类的

OnPrepareDC

函数来告知何时停止。在每次调用OnPrepareDC之后,框架检查CPrintInfo结构的一个名为m_bContinuePrinting的成员。该成员的默认值为TRUE。只要它保持此默认值,框架就继续打印循环。如果它设置为FALSE,框架就停止。若要执行打印时分页,请重写OnPrepareDC以检查是否已到达文档末尾,如果已经到达,则将m_bContinuePrinting设置为FALSE

如果当前页大于 1,OnPrepareDC的默认实现将把m_bContinuePrinting设置为FALSE。这意味着如果未指定文档长度,框架将假设文档的长度为一页。这样做的结果之一就是在调用OnPrepareDC的基类版本时必须谨慎。不要假定m_bContinuePrinting在调用基类版本之后将为TRUE

2:MSDN上的一段示例代码:

// get the default printerCPrintDialog dlg(FALSE);dlg.GetDefaults();// is a default printer set up?HDC hdcPrinter = dlg.GetPrinterDC();if (hdcPrinter == NULL){MessageBox(_T("Buy a printer!"));}else{// create a CDC and attach it to the default printerCDC dcPrinter;dcPrinter.Attach(hdcPrinter);// call StartDoc() to begin printingDOCINFO docinfo;memset(&docinfo, 0, sizeof(docinfo));docinfo.cbSize = sizeof(docinfo);docinfo.lpszDocName = _T("CDC::StartDoc() Code Fragment");// if it fails, complain and exit gracefullyif (dcPrinter.StartDoc(&docinfo) < 0){MessageBox(_T("Printer wouldn't initalize"));}else{// start a pageif (dcPrinter.StartPage() < 0){MessageBox(_T("Could not start page"));dcPrinter.AbortDoc();}else{// actually do some printingCGdiObject* pOldFont = dcPrinter.SelectStockObject(SYSTEM_FONT);dcPrinter.TextOut(50, 50, _T("Hello World!"), 12);dcPrinter.EndPage();dcPrinter.EndDoc();dcPrinter.SelectObject(pOldFont);}}}

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