手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>程序设计>C/C++>列表

VC数据库编程中的打印控制

来源:互联网 作者:west263.com 时间:2008-02-23
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!
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()进行绘制输出的原因。




文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

热点关注
IDC资讯 虚拟主机 域名注册 托管租用 vps主机 智能建站
网站运营 建站经验 策划盈利 搜索优化 网站推广 免费资源
网站联盟 联盟新闻 联盟介绍 联盟点评 网赚技巧
行业资讯 业界动态 搜索引擎 网络游戏 门户动态 电子商务 广告传媒
网络编程 Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术 Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷 Internet Explorer
网页制作 FrontPages Dreamweaver Javascript css photoshop fireworks Flash
程序设计 Java技术 C/C++ VB delphi
网络知识 网络协议 网络安全 网络管理 组网方案 Cisco技术
操作系统 Win2000 WinXP Win2003 Mac OS Linux FreeBSD
返回首页 |关于我们 | 联系我们 | 付款方式 | 创业联盟 | 价格总览 | 资讯中心 | 友情链接 | 网站地图 | 招贤纳士 | RSS