在数据库应用中,一般把纸式报表的打印输出放在比较重要的位置,特别是在银行、保险等金融部门,打印出来的纸式硬拷贝一般都要永久保存,因此程序的打印输出结果是否美观、输出方式是否灵活是衡量程序优劣的重要标志。比起其他编程语言来说,VC编程中的打印控制比较复杂,但它也给程序员最大的灵活性,而这种灵活性正是我们需要的,因为金融部门的报表一般都不太规整,特别是表头部分,二、三重嵌套的情况很常见。下面我们就开发中碰到的一些问题与同行们探讨。
一、 Document/View框架之外的打印
熟悉VC的程序员都知道Microsoft的AppWizard生成的应用程序框架中,可以选择免费的打印及打印预览功能,但是前提是必须选择Document/View结构,然而我们 廯 应用中一般都不需要一个文档类来保存文档,因为数据库(源)就是我们的文档,数据一般是在一个对话框或视中与用户交互,编辑或修改结果直接通过数据库引擎写回数据库中。我们的程序主框架要么是基于对话框的、要么是基于无文档类的单视(或多视)结构,在这种情况下,AppWizard在打印控制部分并不能给我们任何帮助,只能自己负责完成打印控制。
分析MFC提供的打印功能,在一个视中实现定制的打印,需要分别重载视的以下函数:
OnPreparePrinting():在开始打印文档之前,定制或初始化打印对话框;
OnPrepareDC():准备设备场景,分别打印或预览准备PrintDC和ScreenDC;
OnBeginPrinting():开始一次新的打印作业,并分配图形设备接口;
OnEndPrinting(),OnEndPrintPreview():终止打印作业,释放图形设备接口:
OnPrint():完成打印或预览每页文档的输出。
总结起来:一次打印操作要遵循以下步骤:
1.得到或生成打印设备场景,可通过显示打印对话框让用户选择打印机与纸张等设置,也可在程序中直接取系统缺省打印机设置,然后根据报表格式设置纸张大小和打印方向;
2.开始在该设备场景中的一次打印作业,实际打印报表内容,终止打印作业;
3.清除打印设备场景,完成本次打印操作。
在下面的例子中,我们在一个对话框中让用户选择打印某个报表,没有显示打印设置对话框,而是直接取系统缺省打印机设置,然后根据报表格式设置纸张大小和打印方向,之所以这样做是因为金融系统的报表格式一般都是至上而下的统一格式。函数DoPreparePrintDC(),DoPrint()和DoC1earPrintDC()分别对应上述的三个步骤:
BOOL CMyDialog::DoPreparePrintDC() //准备打印场景
{
#define FONTSIZE 14
//获取打印机的设备属性
CPrintDialog dlgPrint(FALSE);
//得到当前系统缺省打印机设置
if(!dlgprint.GetDefau1ts() )return FALSE;
LPDEVMODE pDM=dlgPrint.GetDevMode();
if (pDM==NULL)return FALSE;
//调整打印方向
//pDM- >dm0rientation=DMORIENT_LANDSCAPE(横向)‖
DMORIENT_PORTRAIT(纵向);
//调整纸张大小
//制式纸张:pDM- >dmPaperSize=DMPAPER_A3等;
//或自定义大小:单位:1/10毫米
//pDM- >dmPaperSize=DMPAPER_USER;
//pDM- >dmPaperLength=纸张高度;
//pDM- >dmPaperWidth=纸张宽度;
//解锁由CPrintDialog::GetDevMode()封锁的内存
::GlobalUn1ock(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;
//根据打印机分辨率建立打印字体
//得到每英寸点