《Visual C++ 技术内幕》(第四版)读书笔记
第十八章 打印和打印预览
一、关于最大打印页设置的一点体会
1、对于分页打印,必须在调用OnPrint之前通过CPrintInfo对象pInfo指针的SetMaxPage成员函数来设置最大打印页数。该最大打印页数并不是页面设置的最大打印页数,而是整个文档的最大打印页数。
2、在本书中,作者将这个设置放在视图类的OnPreparePrinting成员函数中的DoPreparePringting之前。
3、但我发现,对于因字体设置、页面设置等不同而导致最大打印页数可能在程序运行过程中发生变化的情况下,OnPrepareDC函数可能是设置最大打印页数更好的选择,这是因为对于字体等GDI对象,必须与特定的设备环境相连,比如说需要取得字符串高度以计算每行的高度以计算每页行数及计算总打印页数,则必须根据具体的设备环境进行相关计算。而在OnPrepaerePringting函数中,无法取得打印机的设备环境,其参数CPrintInfo指针pInfo虽有一个pInfo->m_pPD->m_pd.hDC设备环境句柄,但此时该句柄已释放成为了空句柄,因此我们无法在OnPreparePrinting函数中获取打印机设备环境。
4、而OnPrepareDC函数中,共有两个参数,其中CDC* pDC在屏幕显示时指向显示器设备环境,而在打印时就指向打印机设备环境,CPrintInfo* pInfo指向打印机的当前设置信息,因此在OnPrepareDC中进行设置既可以获得打印机设备环境的指针,又能获得打印机设置信息的指针,对于打印设置来说再合适不过了。但是由于OnPrepareDC是屏幕显示和打印共用的函数,因此问我们有关打印的代码必须包含在如下程序块中:
if(pDC->IsPrinting()){
...
// 打印设置的有关代码
}
否则,在屏幕显示时,程序也会执行打印有关代码,此时因设备环境不匹配,就会引发严重的错误从而导致应用程序崩溃。
同时,该段代码块也应在视图类基类的OnPrepareDC成员函数调用之前。
5、那么是否可在OnPrepareDC中进行相关数据的计算,而在OnPreparePrinting成员函数中进行设置呢,答案是否定的,我们可以通过在程序中设置断点跟踪程序的执行流程,你可以发现,函数OnPrepareDC的执行在OnPreparePrinting之后,实际上载打印时,函数OnPrepareDC就是由函数OnPreparePrinting调用的。
二、在OnInitialUpdate中获取窗口、视口或屏幕大小大小的方法
若需要在函数OnInitialUpdate中获取屏幕大小、窗口大小、视口大小等于设备环境相关的参数,比如说调用GetDeviceCaps、LPToDP、DPToLP、GetWindowExt、GetViewPortExt等函数,若想获得准确地结果,则首先应用当前视图的对象指针this为参数构造一个设备环境(CClientDC或CPaintDC对象均可),然后利用该设备环境对象调用其成员函数来获取相关数据。值得注意的是,若想获得准确地结果,则设备环境构造后必须调用OnPrepareDC,然后再调用以上函数。而对于基类为CScrollView的视图类,OnPrepareDC的调用必须放在SetScrollSize函数调用之后调用,否则程序认为映射模式未设置,出现运行时错误,导致程序无法进行。