---------------------------
VC数据库编程中的打印控制比较复杂,但它也给程序员最大的灵活性,而这种灵活性正是我们需要的。因为各行业、部门的报表一般都不太规整,特别是表头部分,二、三重嵌套的情况很常见。下面我们就开发中碰到的一些问题与同行们探讨。 Document/View框架之外的打印 熟悉VC的程序员都知道Microsoft 的AppWizard生成的应用程序框架中,可以选择免费的打印及打印预览功能,但前提是必须选择Document/View结构。然而我们的数据库应用中一般都不需要一个文档类来保存文档,因为数据库(源)就是我们的文档,数据一般是在一个对话框或视中与用户交互,编辑或修改结果直接通过数据库引擎写回数据库中。我们的程序主框架要么是基于对话框的、要么是基于无文档类的单视(或多视)结构,在这种情况下,AppWizard 在打印控制部分并不能给我们任何帮助,只能自己负责完成打印控制。 总结起来,一次打印操作要遵循以下步骤: 1.得到或生成打印设备场景,可通过显示打印对话框让用户选择打印机与纸张等设置,也可在程序中直接取系统缺省打印机设置,然后根据报表格式设置纸张大小和打印方向; 2.开始在该设备场景中的一次打印作业,实际打印报表内容,终止打印作业; 3.清除打印设备场景,完成本次打印操作。 在下面的例子中,我们在一个对话框中让用户选择打印某个报表,没有显示打印设置对话框,而是直接取系统缺省打印机设置,然后根据报表格式设置纸张大小和打印方向。之所以这样做是因为各行业、部门的报表格式一般都是至上而下的统一格式。函数DoPreparePrintDC()、DoPrint()和DoClearPrintDC()分别对应上述的三个步骤: BOOL CMyDialog::DoPreparePrintDC() // 准备打印场景 { #define FONTSIZE 14 // 获取打印机的设备属性 CPrintDialog dlgPrint( FALSE ); // 得到当前系统缺省打印机设置 if(!dlgPrint.GetDefaults()) return FALSE; LPDEVMODE pDM=dlgPrint.GetDevMode(); if(pDM==NULL) return FALSE; ::GlobalUnlock(pDM); // 联结打印DC,m—hDC是定义为HDC m—hDC的类成员变量 m—hDC=dlgPrint.CreatePrinterDC(); // m—DC是定义为CDC m—DC的类成员变量 if(!m—DC.Attach(m—hDC) return FALSE; // 设置打印标志 m—DC.m—bPrinting=TRUE; short cxInch=m—DC.GetDeviceCaps(LOGPIXELSX); short cyInch=m—DC.GetDeviceCaps(LOGPIXELSY); // 建立打印字体,m—fontPrint 是定义为CFont m_fontPrint的类成员变量 if(!m—fontPrint.CreateFont(MulDiv(FONTSIZE, -cyInch, 72),0,0,0, FW—NORMAL,0,0,0, GB2312—CHARSET, OUT—CHARACTER—PRECIS, CLIP—CHARACTER—PRECIS,DEFAULT—QUALITY, DEFAULT—PITCH|FF—DONTCARE, HFONTNAME) return FALSE; return TRUE;} void CDlgDataPrint::DoClearPrintDC() // 清除打印场景 { m—fontPrint.DeleteObject(); m—DC.Detach(); ::DeleteDC( m—hDC );} void CDlgDataPrint::DoPrint() // 实际打印输出 { if(DoPreparePrintDC()==FALSE) return; // 开始一次打印作业 CString str; str.LoadString(AFX—IDS—APP—TITLE); DOCINFO di; ::ZeroMemory (&di, sizeof (DOCINFO)); di.cbSize=sizeof (DOCINFO); di.lpszDocName=str; m—DC.StartDoc(&di); m—DC.StartPage(); // 将打印字体选进设备场景 CFont* pOldFont=m—DC.SelectObject(&m—fontPrint); // 输出报表,建议用CDC::DrawText()函数便于控制打印范围 ... // 终止打印作业 m—DC.EndPage(); m—DC.EndDoc(); m—DC.SelectObject(pOldFont); // 清除打印场景 DoClearPrintDC();} 表格问题 对格式固定或表头、表体比较复杂的情况,特别是有嵌套表格的情况下,我们认为先将打印结果以文本形式写入一临时文件,然后再对文件进行打印输出的方法会使事情简单一些。因为这样在程序中就可以只关心数据(表体)的输出,而表头则可以固定格式存入数据库。 但是,我们在对文本形式的报表进行打印输出时却发现一个有趣的现象,有时输出结果的相邻两行表格竖线不能对齐,而有时又可以。原来是 Windows 图形输出的问题,只要我们在建立打印字体时,字体的高度是偶数就可保证竖线对齐,如果是奇数则不能对齐。知道了原因,在建立打印字体时只需加入如下代码即可: ... #define FONTSIZE 14 #define HFONTNAME ″宋体″ // 建立打印字体,m—fontPrint是定义为CFont m—fontPrint的类成员变量 int nFontHeight=MulDiv(FONTSIZE,-cyInch, 72); if(nFontHeight % 2) nFontHeight++; if(!m—fontPrint.CreateFont(nFontHeight, 0, 0, 0, FW—NORMAL, 0, 0,0,GB2312—CHARSET, OUT—CHARACTER—PRECIS, CLIP—CHARACTER—PRECIS,DEFAULT—QUALITY, DEFAULT—PITCH | FF—DONTCARE, HFONTNAME)) return FALSE; ... 还有一点小技巧,输出文本形式的报表时,对报表的横线只需要输出其正常高度的二分之一或三分之一,这样报表看起来更紧凑美观。这也是我们在前面建议用CDC::DrawText()进行绘制输出的原因。
VC数据库编程中的打印控制比较复杂,但它也给程序员最大的灵活性,而这种灵活性正是我们需要的。因为各行业、部门的报表一般都不太规整,特别是表头部分,二、三重嵌套的情况很常见。下面我们就开发中碰到的一些问题与同行们探讨。 Document/View框架之外的打印 熟悉VC的程序员都知道Microsoft 的AppWizard生成的应用程序框架中,可以选择免费的打印及打印预览功能,但前提是必须选择Document/View结构。然而我们的数据库应用中一般都不需要一个文档类来保存文档,因为数据库(源)就是我们的文档,数据一般是在一个对话框或视中与用户交互,编辑或修改结果直接通过数据库引擎写回数据库中。我们的程序主框架要么是基于对话框的、要么是基于无文档类的单视(或多视)结构,在这种情况下,AppWizard 在打印控制部分并不能给我们任何帮助,只能自己负责完成打印控制。 总结起来,一次打印操作要遵循以下步骤: 1.得到或生成打印设备场景,可通过显示打印对话框让用户选择打印机与纸张等设置,也可在程序中直接取系统缺省打印机设置,然后根据报表格式设置纸张大小和打印方向; 2.开始在该设备场景中的一次打印作业,实际打印报表内容,终止打印作业; 3.清除打印设备场景,完成本次打印操作。 在下面的例子中,我们在一个对话框中让用户选择打印某个报表,没有显示打印设置对话框,而是直接取系统缺省打印机设置,然后根据报表格式设置纸张大小和打印方向。之所以这样做是因为各行业、部门的报表格式一般都是至上而下的统一格式。函数DoPreparePrintDC()、DoPrint()和DoClearPrintDC()分别对应上述的三个步骤: BOOL CMyDialog::DoPreparePrintDC() // 准备打印场景 { #define FONTSIZE 14 // 获取打印机的设备属性 CPrintDialog dlgPrint( FALSE ); // 得到当前系统缺省打印机设置 if(!dlgPrint.GetDefaults()) return FALSE; LPDEVMODE pDM=dlgPrint.GetDevMode(); if(pDM==NULL) return FALSE; ::GlobalUnlock(pDM); // 联结打印DC,m—hDC是定义为HDC m—hDC的类成员变量 m—hDC=dlgPrint.CreatePrinterDC(); // m—DC是定义为CDC m—DC的类成员变量 if(!m—DC.Attach(m—hDC) return FALSE; // 设置打印标志 m—DC.m—bPrinting=TRUE; short cxInch=m—DC.GetDeviceCaps(LOGPIXELSX); short cyInch=m—DC.GetDeviceCaps(LOGPIXELSY); // 建立打印字体,m—fontPrint 是定义为CFont m_fontPrint的类成员变量 if(!m—fontPrint.CreateFont(MulDiv(FONTSIZE, -cyInch, 72),0,0,0, FW—NORMAL,0,0,0, GB2312—CHARSET, OUT—CHARACTER—PRECIS, CLIP—CHARACTER—PRECIS,DEFAULT—QUALITY, DEFAULT—PITCH|FF—DONTCARE, HFONTNAME) return FALSE; return TRUE;} void CDlgDataPrint::DoClearPrintDC() // 清除打印场景 { m—fontPrint.DeleteObject(); m—DC.Detach(); ::DeleteDC( m—hDC );} void CDlgDataPrint::DoPrint() // 实际打印输出 { if(DoPreparePrintDC()==FALSE) return; // 开始一次打印作业 CString str; str.LoadString(AFX—IDS—APP—TITLE); DOCINFO di; ::ZeroMemory (&di, sizeof (DOCINFO)); di.cbSize=sizeof (DOCINFO); di.lpszDocName=str; m—DC.StartDoc(&di); m—DC.StartPage(); // 将打印字体选进设备场景 CFont* pOldFont=m—DC.SelectObject(&m—fontPrint); // 输出报表,建议用CDC::DrawText()函数便于控制打印范围 ... // 终止打印作业 m—DC.EndPage(); m—DC.EndDoc(); m—DC.SelectObject(pOldFont); // 清除打印场景 DoClearPrintDC();} 表格问题 对格式固定或表头、表体比较复杂的情况,特别是有嵌套表格的情况下,我们认为先将打印结果以文本形式写入一临时文件,然后再对文件进行打印输出的方法会使事情简单一些。因为这样在程序中就可以只关心数据(表体)的输出,而表头则可以固定格式存入数据库。 但是,我们在对文本形式的报表进行打印输出时却发现一个有趣的现象,有时输出结果的相邻两行表格竖线不能对齐,而有时又可以。原来是 Windows 图形输出的问题,只要我们在建立打印字体时,字体的高度是偶数就可保证竖线对齐,如果是奇数则不能对齐。知道了原因,在建立打印字体时只需加入如下代码即可: ... #define FONTSIZE 14 #define HFONTNAME ″宋体″ // 建立打印字体,m—fontPrint是定义为CFont m—fontPrint的类成员变量 int nFontHeight=MulDiv(FONTSIZE,-cyInch, 72); if(nFontHeight % 2) nFontHeight++; if(!m—fontPrint.CreateFont(nFontHeight, 0, 0, 0, FW—NORMAL, 0, 0,0,GB2312—CHARSET, OUT—CHARACTER—PRECIS, CLIP—CHARACTER—PRECIS,DEFAULT—QUALITY, DEFAULT—PITCH | FF—DONTCARE, HFONTNAME)) return FALSE; ... 还有一点小技巧,输出文本形式的报表时,对报表的横线只需要输出其正常高度的二分之一或三分之一,这样报表看起来更紧凑美观。这也是我们在前面建议用CDC::DrawText()进行绘制输出的原因。
解决方案 »
- 为什么UpdateData函数在外部定义的头文件中函数中提示如下
- 问 同步异步阻塞非阻塞 各自的优缺点
- 在EDIT BOX内画图的一个问题
- WIN32程序中,模拟键盘Backspace按键的消息是什么啊?请高手指点!
- 怎样设计WIN98中“科学”那样的屏幕保护?
- C++的不足之处讨论系列(一):虚拟函数(转贴)
- 征求幂运算的算法,希望有详细的解释和代码范例,谢谢!
- 请问大家在DX中怎样把一个surface左右翻转blt到另一个surface?
- A4纸的大小是210 x 297mm,我在vc里想开一个同样大小的窗口,请问代码如何实现?
- 如何定义两个互相引用的类?
- 大家来看看(其实我不懂)!
- 密码探测器的原理是什么?
< http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;Q162609>HOWTO: Customize the Common Print Dialog Box
<http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;Q132909>HOWTO: How to Change Default Printer Settings in an MFC Application
<http://support.microsoft.com/directory/article.asp?ID=KB;EN-US;Q126897>
微软全球技术中心 VC技术支持
本贴子仅供CSDN的用户作为参考信息使用。其内容不具备任何法律保障。您需要考虑到并承担使用此信息可能带来的风险。具体事项可参见使用条款 (http://www.csdn.net/microsoft/terms.shtm)。