Visual C++6.0是开发Windows应用程序的强大工具,但是要通过它实现程序的打印功能,一直是初学者的一个难点,经常有朋友询问如何在VC中实现打印功能,他们往往感到在MFC提供的框架内实现这个问题很复杂,不知道如何下手。本例针对这个问题,介绍一种简单的方法实现文字串的打印功能,读者朋友可以在此基础上稍微改动一下,就可以实现文件、图像的打印功能。

  一、实现方法

  在Windows操作系统下,显示器、打印机和绘图仪都被视为输出设备,正常情况下,系统默认的输出设备是显示器。要使用打印机,首先需要创建一个指向打印机的设备环境句柄,然后通过该句柄调用相关的绘图函数把所需的文字和图形输出至打印机上。当打印结束后,删除这个设备环境句柄即可。

  当Windows系统中安装好打印机后,系统总是自动设置一个打印机为系统的默认打印机,在Windows的启动配置文件Win.ini中的[window]段中列出了带有关键字device的默认打印机。下面是某一机器中Win.ini中的[Windows]字段的内容:

[windows]
load=
run=
NullPort=None
device=HP LaserJet 4050(computer000),HPBFDB1,LPT1

  在上述关键字device后的字符串中,包含了系统中默认打印机的三个重要属性,它们依次是打印机的设备名HP LaserJet 4050(computer000),驱动程序名是HPBFDB1,输出端口为LPT1。

  为了操纵系统默认的打印机,实现程序的打印功能,在程序中可调用API函数GetProfileString()从Win.ini文件中获得device这个设备字符串,该函数的原型为:DWORD GetProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize)。函数中lpAppName参数为所要检索的Win.ini文件中的字段名;lpKeyName为字段中的关键字名;lpDefault为默认的字符串;lpReturnedString为检索到的字符串,如果该函数没有从lpKeyName关键字中检索到相应的字符串,则kpRetrunedString返回默认字符串lpDefault;nSize为返回字符串的长度。

  获取上述字符串后,再使用strtok()函数将该字符串进行分解,获得与打印机相关的三个属性,作为API函数CreateDC()创建打印机设备环境句柄的参数,CreateDC()函数如果调用成功,则为默认打印机创建一个设备环境句柄,否则返回一个空值(NULL)。该函数的原形为:HDC CreateDC(LPCTSTR lpszDriver,LPCTSTR lpszDevice,LPCTSTR lpszOutput,CONST DEVMODE *lpinitData)。该函数的前三个参数恰好对应打印机的三个属性,最后一个参数为初始化打印机驱动程序的数据,一般情况下该参数设置为NULL就可以了。

  在具体打印的过程中,调用int StartDoc( HDC hdc, CONST DOCINFO *lpdi )函数来开始一个打印任务,其中参数lpdi为一个指向DOCINFO结构的指针,该结构如下:

typedef struct { 
 int cbSize; //结构的尺寸大小;
 LPCTSTR lpszDocName; //文档的名字;
 LPCTSTR lpszOutput; //输出文档名,一般情况下为NULL;
 LPCTSTR lpszDatatype;//用来记录打印过程的数据类型,一般情况下为NULL;
 DWORD fwType; //用来支持打印工作的额外

信息,一般情况下为NULL;
} DOCINFO, *LPDOCINFO; 
  开始一个打印任务后,再调用StartPage(hdcprint)函数让打印机走纸,通知打印机有文档将要打印;接下来的工作就是输出数据了,这部分工作对于开发人员来说就象往计算机屏幕上输出文字、图像一样容易,只不过是计算机根据当前的设备环境句柄自动将数据输出到打印机罢了。数据打印完后,需要作一些善后处理工作,使用RestoreDC(hdcprint,-1)函数恢复打印机设备句柄、EndPage(hdcprint)函数让打印机停止打印,最后调用EndDoc(hdcprint)函数结束上述的打印作业。

  二、编程步骤

  1、启动Visual C++6.0,新建一个基于对话框的应用程序Test,在程序的对话框窗体中加入一个按钮(Button),设置这个Button的属性:ID=IDC_PRINT,CAPTION="打印";

  2、使用Class Wizard类向导为该按钮添加一个鼠标单击处理函数OnPrint()

  3、修改TestDlg.cpp文件中的OnPrint()函数;

  4、添加代码,编译运行程序。

==========================================================================================================================

在打印预览对话框类中

  1. extern int nPaperSize_X ;
  2. extern int nPaperSize_Y ;
  3. extern int nOneLines;
  4. extern int nNextLines;
  5. //打印结构
  6. typedef struct
  7. {
  8. int  nMaxLine;   //最大行数
  9. int  nCountPage;   //一共页数
  10. int  nCurPage;   //当前页码
  11. BOOL IsPrint;   //是否打印
  12. HWND hWnd;    //窗口句柄
  13. HWND hListView;   //列表控件句柄
  14. TCHAR szTag[256];   //其它数据
  15. int  nTag;    //其它数据
  16. LPVOID lpVoid;    //其它数据
  17. CGridCtrlEx *pObj;   //区分是月报表还是日报表
  18. }PRNINFO, *PPRNINFO;
  1. //回调函数,设置打印属性
  2. void CPreviewParentDlg::SetCallBackFun( PRINTPREVIEW pFun, PRNINFO &sPrnInfo )
  3. {
  4. memcpy(&m_PrnInfo, &sPrnInfo, sizeof(PRNINFO));
  5. m_pDrawInfoFun = pFun;
  6. m_nCount = m_PrnInfo.nMaxLine;  // 总的行数
  7. m_nCountPage = 1;
  8. int m = m_nCount-m_OneCount;
  9. int n = m/m_NextCount;
  10. m_nCountPage += n;
  11. n = m%m_NextCount;
  12. if(n>0)
  13. m_nCountPage++;   // 页数
  14. m_PrnInfo.nCountPage = m_nCountPage;
  15. sPrnInfo.nCountPage = m_nCountPage;
  16. }
  1. void CPreviewChildDlg::PrintDoc()
  2. {
  3. NotifyDlg Ndlg(_T("决定打印当前报表吗?"), TRUE);
  4. if (Ndlg.DoModal() == IDCANCEL)
  5. return;
  6. PRINTDLG printInfo;
  7. ZeroMemory(&printInfo,sizeof(printInfo));  //清空该结构
  8. printInfo.lStructSize = sizeof(printInfo);
  9. printInfo.hwndOwner = 0;
  10. printInfo.hDevMode = 0;
  11. printInfo.hDevNames = 0;
  12. //这个是关键,PD_RETURNDC 如果不设这个标志,就拿不到hDC了
  13. //            PD_RETURNDEFAULT 这个就是得到默认打印机,不需要弹设置对话框
  14. printInfo.Flags = PD_RETURNDC | PD_RETURNDEFAULT | PD_ALLPAGES;
  15. PrintDlg(&printInfo);//调用API拿出默认打印机
  16. DWORD rst = CommDlgExtendedError();//看看出错没有
  17. if(rst != 0)
  18. {//出错了,清空标志再次调用API,此时就会弹出打印设置对话框供用户选择了
  19. printInfo.Flags = 0;
  20. PrintDlg(&printInfo);
  21. }
  22. HDC printDC=printInfo.hDC; //得到打印DC,输出到打印,
  23. CDC MemDc;
  24. MemDc.Attach(printDC);
  25. if(m_pDrawInfoFun!= NULL)
  26. {
  27. m_PrnInfo.IsPrint = TRUE;  // 用打印机打印
  28. m_PrnInfo.nCurPage = m_CurPage;
  29. m_PrnInfo.nCountPage = m_CountPage;
  30. m_pDrawInfoFun(MemDc, m_PrnInfo);
  31. }
  32. MemDc.DeleteDC();}
  1. //刷新预览区
  2. void CPreviewChildDlg::OnPaint()
  3. {
  4. CPaintDC dc(this); // device context for painting
  5. // TODO: Add your message handler code here
  6. CClientDC dlgDC(this);
  7. SetWindowOrgEx(dlgDC.m_hDC, m_xPt, m_yPt, NULL);
  8. CDC MemDc;
  9. MemDc.CreateCompatibleDC(NULL);
  10. CBitmap cBitmap;
  11. int xP = dlgDC.GetDeviceCaps(LOGPIXELSX);
  12. int yP = dlgDC.GetDeviceCaps(LOGPIXELSY);
  13. DOUBLE xPix = (DOUBLE)xP*10/254;    //每 mm 宽度的像素
  14. DOUBLE yPix = (DOUBLE)yP*10/254;    //每 mm 高度的像素
  15. cBitmap.CreateCompatibleBitmap(&dlgDC, nPaperSize_X*xPix, nPaperSize_Y*yPix);
  16. MemDc.SelectObject(&cBitmap);
  17. if(m_pDrawInfoFun!= NULL)
  18. {
  19. m_PrnInfo.IsPrint = FALSE;  //显示的是 预览窗口
  20. m_PrnInfo.nCurPage = m_CurPage;
  21. m_pDrawInfoFun(MemDc, m_PrnInfo);   //调用回调函数
  22. }
  23. dlgDC.BitBlt(xP/2, yP/2, nPaperSize_X*xPix+xP/2, nPaperSize_Y*yPix+yP/2, &MemDc, 0, 0, SRCCOPY);
  24. MemDc.DeleteDC();
  25. cBitmap.DeleteObject();
  26. // Do not call CDialog::OnPaint() for painting messages
  27. }

=============调用打印功能类

  1. void CAttendReportDlg::PrintData()
  2. {
  3. CGridCtrlEx *pGridCtrl = NULL;
  4. BOOL bDay = FALSE;
  5. if ( ((CButton*)GetDlgItem(IDC_RADIO_DAY))->GetCheck() )
  6. {
  7. pGridCtrl = m_pDayGridCtrl;
  8. bDay = TRUE;
  9. }
  10. else if ( ((CButton*)GetDlgItem(IDC_RADIO_MONTH))->GetCheck() )
  11. {
  12. pGridCtrl = m_pMonGridCtrl;
  13. }
  14. if( pGridCtrl->GetRowCount() <= 1 )    // 没有记录
  15. return;
  16. ///选择打印机对话框
  17. CDC MemDc;
  18. HDC hdcPrint = NULL;
  19. CPrintDialog dlg(FALSE);
  20. if (m_bPrint)  //打印按钮,不弹出选择对话框,获取默认打印设备
  21. {
  22. PRINTDLG printInfo;
  23. ZeroMemory(&printInfo,sizeof(printInfo));  //清空该结构
  24. printInfo.lStructSize = sizeof(printInfo);
  25. printInfo.hwndOwner = 0;
  26. printInfo.hDevMode = 0;
  27. printInfo.hDevNames = 0;
  28. //这个是关键,PD_RETURNDC 如果不设这个标志,就拿不到hDC了
  29. //PD_RETURNDEFAULT 这个就是得到默认打印机,不需要弹出设置对话框
  30. printInfo.Flags = PD_RETURNDC | PD_RETURNDEFAULT | PD_ALLPAGES;
  31. PrintDlg(&printInfo);//调用API拿出默认打印机
  32. DWORD rst = CommDlgExtendedError();//看看出错没有
  33. if(rst != 0)
  34. {//出错了,清空标志再次调用API,此时就会弹出打印设置对话框供用户选择了
  35. printInfo.Flags = 0;
  36. PrintDlg(&printInfo);
  37. }
  38. hdcPrint=printInfo.hDC; //得到打印DC,输出到打印
  39. }
  40. else  //弹出对话框选择打印设备
  41. {
  42. dlg.DoModal();
  43. hdcPrint = dlg.GetPrinterDC();
  44. }
  45. if(hdcPrint == NULL)
  46. {
  47. NotifyDlg Ndlg(_T("打印机初始化失败!"));
  48. Ndlg.DoModal();
  49. return;
  50. }
  51. MemDc.Attach(hdcPrint);
  52. nPaperSize_X = MemDc.GetDeviceCaps(HORZSIZE);    // 纸张宽度
  53. nPaperSize_Y = MemDc.GetDeviceCaps(VERTSIZE);    // 纸张高度
  54. int xP = GetDeviceCaps(MemDc.m_hDC, LOGPIXELSX);    //x方向每英寸像素点数
  55. int yP = GetDeviceCaps(MemDc.m_hDC, LOGPIXELSY);    //y方向每英寸像素点数
  56. int xPix = (DOUBLE)xP*10/254;   //每 mm 宽度的像素
  57. int yPix = (DOUBLE)yP*10/254;   //每 mm 高度的像素
  58. DOUBLE fAdd = 5*yPix;       //每格递增量
  59. nOneLines = (nPaperSize_Y * 0.85*yPix)/fAdd;
  60. nNextLines = (nPaperSize_Y * 0.85*yPix)/fAdd+1;
  61. PRNINFO PrnInfo = {0};
  62. PrnInfo.hListView = NULL;
  63. PrnInfo.hWnd = this->m_hWnd;
  64. PrnInfo.IsPrint = m_bPrint;
  65. PrnInfo.nCurPage = 1;
  66. PrnInfo.nMaxLine = pGridCtrl->GetRowCount()-1;
  67. PrnInfo.pObj = pGridCtrl;
  68. CPreviewParentDlg DlgPreView;
  69. CPreviewChildDlg DlgChildPreView;
  70. if (bDay)
  71. {
  72. DlgPreView.SetCallBackFun(PrintDayInfo, PrnInfo);  //回调函数,设置打印或预览函数,及纸张排版信息
  73. DlgChildPreView.SetCallBackFun(PrintDayInfo, PrnInfo);
  74. }
  75. else
  76. {
  77. DlgPreView.SetCallBackFun(PrintMonInfo, PrnInfo);
  78. DlgChildPreView.SetCallBackFun(PrintMonInfo, PrnInfo);
  79. }
  80. if (!m_bPrint)
  81. {
  82. DlgPreView.DoModal();
  83. }
  84. else
  85. {
  86. DlgChildPreView.PrintDoc();
  87. }
  88. MemDc.DeleteDC();
  89. }
  90. void CAttendReportDlg::PrintDayInfo( CDC &memDC, PRNINFO PrnInfo )
  91. {
  92. if(memDC.m_hDC == NULL)
  93. return;
  94. int nCurPage = PrnInfo.nCurPage;    //当前页
  95. BOOL IsPrint = PrnInfo.IsPrint;     //是否打印
  96. int nMaxPage = PrnInfo.nCountPage;  //最大页码
  97. HWND hWnd = PrnInfo.hWnd;
  98. CString csLFinality, csRFinality;
  99. CGridCtrlEx *pGridCtrl = PrnInfo.pObj;
  100. CTime time = CTime::GetCurrentTime();
  101. csLFinality = time.Format(_T("%Y-%m-%d %H:%M:%S"));
  102. csLFinality = _T("报表日期:") + csLFinality;
  103. csRFinality.Format(_T("第 %i 页/共 %i 页"), nCurPage, nMaxPage);
  104. TCHAR szTitle[] = _T("考 勤 日 报 表");
  105. CRect rc, rt1, rt2, rt3, rt4, rt5, rt6, rt7, rt8, rt9, rt10;
  106. CPen *hPenOld;
  107. CPen cPen;
  108. CFont TitleFont, DetailFont, *oldfont;
  109. //标题字体
  110. TitleFont.CreateFont(-MulDiv(14,memDC.GetDeviceCaps(LOGPIXELSY),72),
  111. 0,0,0,FW_NORMAL,0,0,0,GB2312_CHARSET,
  112. OUT_STROKE_PRECIS,CLIP_STROKE_PRECIS,DRAFT_QUALITY,
  113. VARIABLE_PITCH|FF_SWISS,_T("黑体"));
  114. //细节字体
  115. DetailFont.CreateFont(-MulDiv(10,memDC.GetDeviceCaps(LOGPIXELSY),92),
  116. 0,0,0,FW_NORMAL,0,0,0,GB2312_CHARSET,
  117. OUT_STROKE_PRECIS,CLIP_STROKE_PRECIS,DRAFT_QUALITY,
  118. VARIABLE_PITCH|FF_SWISS,_T("宋体"));
  119. //粗笔
  120. cPen.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
  121. int xP = GetDeviceCaps(memDC.m_hDC, LOGPIXELSX);    //x方向每英寸像素点数
  122. int yP = GetDeviceCaps(memDC.m_hDC, LOGPIXELSY);    //y方向每英寸像素点数
  123. DOUBLE xPix = (DOUBLE)xP*10/254;    //每 mm 宽度的像素
  124. DOUBLE yPix = (DOUBLE)yP*10/254;    //每 mm 高度的像素
  125. DOUBLE fAdd = 5*yPix;       //每格递增量
  126. DOUBLE nTop = 30*yPix;      //第一页最上线
  127. int   iStart = 0;           //从第几行开始读取
  128. DOUBLE nBottom = nTop+nOneLines*fAdd;
  129. if(nCurPage != 1)
  130. nTop = 30*yPix-fAdd;    //非第一页最上线
  131. if(nCurPage == 2)
  132. iStart = nOneLines;
  133. if(nCurPage>2)
  134. iStart = nOneLines+(nCurPage - 2)*nNextLines;
  135. DOUBLE nLeft = 15*xPix;         //最左线
  136. DOUBLE nRight = xPix*(nPaperSize_X-15); //最右线
  137. DOUBLE nItemWide = ((nPaperSize_X-30)/14)*xPix;
  138. DOUBLE nTextAdd = 1.5*xPix;
  139. if(IsPrint)
  140. {
  141. //真正打印部分
  142. static DOCINFO di = {sizeof (DOCINFO),  szTitle} ;
  143. //开始文档打印/////////////////////////////////////////     start print
  144. //////////////////////////////////////////////////////////
  145. if(memDC.StartDoc( &di ) < 0) // startdoc-----enddoc
  146. {
  147. NotifyDlg dlg(_T("连接到打印机化败!"));
  148. dlg.DoModal();
  149. }
  150. else
  151. {
  152. iStart = 0;
  153. nTop = 30*yPix;     //第一页最上线
  154. for(int iTotalPages = 1; iTotalPages<=nMaxPage; iTotalPages++)
  155. {
  156. int nCurPage = iTotalPages;
  157. csRFinality.Format(_T("第 %i 页/共 %i 页"), nCurPage, nMaxPage);
  158. time=CTime::GetCurrentTime();
  159. csLFinality = time.Format(_T("%Y-%m-%d %H:%M:%S"));
  160. csLFinality = _T("报表日期:") + csLFinality;
  161. if(nCurPage != 1)
  162. nTop = 30*yPix-fAdd;    //非第一页最上线
  163. if(nCurPage == 2)
  164. iStart = nOneLines;
  165. if(nCurPage>2)
  166. iStart = nOneLines+(nCurPage - 2)*nNextLines;
  167. //开始页
  168. if(memDC.StartPage() < 0)
  169. {
  170. NotifyDlg dlg(_T("打印失败!"));
  171. dlg.DoModal();
  172. memDC.AbortDoc();
  173. return;
  174. }
  175. else
  176. {
  177. //打印
  178. //标题
  179. oldfont = memDC.SelectObject(&TitleFont);
  180. int nItem = nNextLines;
  181. if(nCurPage == 1)
  182. {
  183. nItem = nOneLines;
  184. rc.SetRect(0, yPix*15, nPaperSize_X*xPix, yPix*25);
  185. memDC.DrawText(szTitle, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  186. }
  187. //细节
  188. memDC.SelectObject(&DetailFont);
  189. rc.SetRect(nLeft, nTop, nRight, nTop+fAdd);
  190. //上横线
  191. memDC.MoveTo(rc.left, rc.top);
  192. memDC.LineTo(rc.right, rc.top);
  193. rt1.SetRect(nLeft, nTop, rc.right -12.4*nItemWide , nTop+fAdd);     //编 号
  194. rt2.SetRect(rt1.right, rt1.top, rt1.right + 1.5*nItemWide, rt1.bottom); //姓名
  195. rt3.SetRect(rt2.right, rt1.top, rt2.right + 1.5*nItemWide, rt1.bottom); //考勤日期
  196. rt4.SetRect(rt3.right, rt1.top, rt3.right + 2.2*nItemWide, rt1.bottom); //班次
  197. rt5.SetRect(rt4.right, rt1.top, rt4.right + 1.6*nItemWide, rt1.bottom); //时段
  198. rt6.SetRect(rt5.right, rt1.top, rt5.right + 1.6*nItemWide, rt1.bottom); //考勤时间
  199. rt7.SetRect(rt6.right, rt1.top, rt6.right + nItemWide, rt1.bottom); //迟到(分)
  200. rt8.SetRect(rt7.right, rt1.top, rt7.right + nItemWide, rt1.bottom); //早退(分)
  201. rt9.SetRect(rt8.right, rt1.top, rt8.right + nItemWide, rt1.bottom); //旷工(分)
  202. rt10.SetRect(rt9.right, rt1.top, rc.right, rt1.bottom); //请假(分)
  203. memDC.DrawText(_T("编 号"), &rt1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  204. memDC.DrawText(_T("姓 名"), &rt2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  205. memDC.DrawText(_T("考勤日期"), &rt3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  206. memDC.DrawText(_T("班 次"), &rt4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  207. memDC.DrawText(_T("时 段"), &rt5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  208. memDC.DrawText(_T("考勤时间"), &rt6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  209. memDC.DrawText(_T("迟到(分)"), &rt7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  210. memDC.DrawText(_T("早退(分)"), &rt8, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  211. memDC.DrawText(_T("旷工(分)"), &rt9, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  212. memDC.DrawText(_T("请假(分)"), &rt10, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  213. memDC.MoveTo(rt1.right, rt1.top);
  214. memDC.LineTo(rt1.right, rt1.bottom);
  215. memDC.MoveTo(rt2.right, rt1.top);
  216. memDC.LineTo(rt2.right, rt1.bottom);
  217. memDC.MoveTo(rt3.right, rt1.top);
  218. memDC.LineTo(rt3.right, rt1.bottom);
  219. memDC.MoveTo(rt4.right, rt1.top);
  220. memDC.LineTo(rt4.right, rt1.bottom);
  221. memDC.MoveTo(rt5.right, rt1.top);
  222. memDC.LineTo(rt5.right, rt1.bottom);
  223. memDC.MoveTo(rt6.right, rt1.top);
  224. memDC.LineTo(rt6.right, rt1.bottom);
  225. memDC.MoveTo(rt7.right, rt1.top);
  226. memDC.LineTo(rt7.right, rt1.bottom);
  227. memDC.MoveTo(rt8.right, rt1.top);
  228. memDC.LineTo(rt8.right, rt1.bottom);
  229. memDC.MoveTo(rt9.right, rt1.top);
  230. memDC.LineTo(rt9.right, rt1.bottom);
  231. memDC.MoveTo(rc.left, rt1.bottom);
  232. memDC.LineTo(rc.right, rt1.bottom);
  233. CString strID, strName, strDate, strSID, strTime, strAttTime, strLate, strEarlier, strAbsent, strLeave;
  234. rc.SetRect(nLeft, nTop+fAdd, nRight, nTop+2*fAdd);
  235. rt1.SetRect(nLeft+nTextAdd, rc.top, rc.right-12.4*nItemWide, rc.bottom);
  236. rt2.SetRect(rt1.right+nTextAdd, rt1.top, rt1.right + 1.5*nItemWide, rt1.bottom);
  237. rt3.SetRect(rt2.right+nTextAdd, rt1.top, rt2.right + 1.5*nItemWide, rt1.bottom);
  238. rt4.SetRect(rt3.right+nTextAdd, rt1.top, rt3.right + 2.2*nItemWide, rt1.bottom);
  239. rt5.SetRect(rt4.right+nTextAdd, rt1.top, rt4.right +1.6*nItemWide, rt1.bottom);
  240. rt6.SetRect(rt5.right+nTextAdd, rt1.top, rt5.right + 1.6*nItemWide, rt1.bottom);
  241. rt7.SetRect(rt6.right+nTextAdd, rt1.top, rt6.right + nItemWide, rt1.bottom);
  242. rt8.SetRect(rt7.right+nTextAdd, rt1.top, rt7.right + nItemWide, rt1.bottom);
  243. rt9.SetRect(rt8.right+nTextAdd, rt1.top, rt8.right + nItemWide, rt1.bottom);
  244. rt10.SetRect(rt9.right+nTextAdd, rt1.top, rc.right, rt1.bottom);
  245. int nCountItem = pGridCtrl->GetRowCount();
  246. for(int i=1;i<nItem; i++)
  247. {
  248. strID = pGridCtrl->GetItemText(i+iStart, 1);
  249. strName = pGridCtrl->GetItemText(i+iStart, 2);
  250. strDate = pGridCtrl->GetItemText(i+iStart, 3);
  251. strSID = pGridCtrl->GetItemText(i+iStart, 4);
  252. strTime = pGridCtrl->GetItemText(i+iStart, 5);
  253. strAttTime = pGridCtrl->GetItemText(i+iStart, 6);
  254. strLate = pGridCtrl->GetItemText(i+iStart, 7);
  255. strEarlier = pGridCtrl->GetItemText(i+iStart, 8);
  256. strAbsent = pGridCtrl->GetItemText(i+iStart, 9);
  257. strLeave = pGridCtrl->GetItemText(i+iStart, 10);
  258. memDC.DrawText(strID, &rt1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  259. memDC.DrawText(strName, &rt2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  260. memDC.DrawText(strDate, &rt3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  261. memDC.DrawText(strSID, &rt4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  262. memDC.DrawText(strTime, &rt5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  263. memDC.DrawText(strAttTime, &rt6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  264. memDC.DrawText(strLate, &rt7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  265. memDC.DrawText(strEarlier, &rt8, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  266. memDC.DrawText(strAbsent, &rt9, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  267. memDC.DrawText(strLeave, &rt10, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  268. //下横线
  269. memDC.MoveTo(rc.left, rc.bottom);
  270. memDC.LineTo(rc.right, rc.bottom);
  271. memDC.MoveTo(rt1.right, rt1.top);
  272. memDC.LineTo(rt1.right, rt1.bottom);
  273. memDC.MoveTo(rt2.right, rt1.top);
  274. memDC.LineTo(rt2.right, rt1.bottom);
  275. memDC.MoveTo(rt3.right, rt1.top);
  276. memDC.LineTo(rt3.right, rt1.bottom);
  277. memDC.MoveTo(rt4.right, rt1.top);
  278. memDC.LineTo(rt4.right, rt1.bottom);
  279. memDC.MoveTo(rt5.right, rt1.top);
  280. memDC.LineTo(rt5.right, rt1.bottom);
  281. memDC.MoveTo(rt6.right, rt1.top);
  282. memDC.LineTo(rt6.right, rt1.bottom);
  283. memDC.MoveTo(rt7.right, rt1.top);
  284. memDC.LineTo(rt7.right, rt1.bottom);
  285. memDC.MoveTo(rt8.right, rt1.top);
  286. memDC.LineTo(rt8.right, rt1.bottom);
  287. memDC.MoveTo(rt9.right, rt1.top);
  288. memDC.LineTo(rt9.right, rt1.bottom);
  289. memDC.MoveTo(rc.left, rt1.bottom);
  290. memDC.LineTo(rc.right, rt1.bottom);
  291. rc.top += fAdd;
  292. rc.bottom += fAdd;
  293. rt1.top = rc.top;
  294. rt1.bottom = rc.bottom;
  295. rt2.top = rt1.top;
  296. rt2.bottom = rt1.bottom;
  297. rt3.top = rt1.top;
  298. rt3.bottom = rt1.bottom;
  299. rt4.top = rt1.top;
  300. rt4.bottom = rt1.bottom;
  301. rt5.top = rt1.top;
  302. rt5.bottom = rt1.bottom;
  303. rt6.top = rt1.top;
  304. rt6.bottom = rt1.bottom;
  305. rt7.top = rt1.top;
  306. rt7.bottom = rt1.bottom;
  307. rt8.top = rt1.top;
  308. rt8.bottom = rt1.bottom;
  309. rt9.top = rt1.top;
  310. rt9.bottom = rt1.bottom;
  311. rt10.top = rt1.top;
  312. rt10.bottom = rt1.bottom;
  313. if((i+iStart+1)>=nCountItem)
  314. break;
  315. }
  316. //结尾
  317. memDC.MoveTo(rc.left, nTop);
  318. memDC.LineTo(rc.left, rc.top);
  319. memDC.MoveTo(rc.right, nTop);
  320. memDC.LineTo(rc.right, rc.top);
  321. memDC.DrawText(csLFinality, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
  322. memDC.DrawText(csRFinality, &rc, DT_RIGHT| DT_VCENTER | DT_SINGLELINE);
  323. memDC.EndPage();
  324. memDC.SelectObject(oldfont);
  325. }
  326. }
  327. memDC.EndDoc();
  328. }
  329. }
  330. else
  331. {
  332. ////////////////////打印预览
  333. //边框线
  334. hPenOld = memDC.SelectObject(&cPen);
  335. rc.SetRect(0, 0, nPaperSize_X*xPix, nPaperSize_Y*yPix);
  336. memDC.Rectangle(&rc);
  337. memDC.SelectObject(hPenOld);
  338. //标题
  339. oldfont = memDC.SelectObject(&TitleFont);
  340. int nItem = nNextLines;
  341. if(nCurPage == 1)
  342. {
  343. nItem = nOneLines;
  344. rc.SetRect(0, yPix*15, nPaperSize_X*xPix, yPix*25);
  345. memDC.DrawText(szTitle, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  346. }
  347. //细节
  348. memDC.SelectObject(&DetailFont);
  349. rc.SetRect(nLeft, nTop, nRight, nTop+fAdd);
  350. //上横线
  351. memDC.MoveTo(rc.left, rc.top);
  352. memDC.LineTo(rc.right, rc.top);
  353. rt1.SetRect(nLeft, nTop, rc.right -12.2*nItemWide, nTop+fAdd);      //编 号
  354. rt2.SetRect(rt1.right, rt1.top, rt1.right + 1.5*nItemWide, rt1.bottom); //姓名
  355. rt3.SetRect(rt2.right, rt1.top, rt2.right + 1.5*nItemWide, rt1.bottom); //考勤日期
  356. rt4.SetRect(rt3.right, rt1.top, rt3.right + 2*nItemWide, rt1.bottom);   //班次
  357. rt5.SetRect(rt4.right, rt1.top, rt4.right + 1.6*nItemWide, rt1.bottom); //时段
  358. rt6.SetRect(rt5.right, rt1.top, rt5.right + 1.6*nItemWide, rt1.bottom); //考勤时间
  359. rt7.SetRect(rt6.right, rt1.top, rt6.right + nItemWide, rt1.bottom); //迟到(分)
  360. rt8.SetRect(rt7.right, rt1.top, rt7.right + nItemWide, rt1.bottom); //早退(分)
  361. rt9.SetRect(rt8.right, rt1.top, rt8.right + nItemWide, rt1.bottom); //旷工(分)
  362. rt10.SetRect(rt9.right, rt1.top, rc.right, rt1.bottom); //请假(分)
  363. memDC.DrawText(_T("编 号"), &rt1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  364. memDC.DrawText(_T("姓 名"), &rt2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  365. memDC.DrawText(_T("考勤日期"), &rt3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  366. memDC.DrawText(_T("班 次"), &rt4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  367. memDC.DrawText(_T("时 段"), &rt5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  368. memDC.DrawText(_T("考勤时间"), &rt6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  369. memDC.DrawText(_T("迟到(分)"), &rt7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  370. memDC.DrawText(_T("早退(分)"), &rt8, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  371. memDC.DrawText(_T("旷工(分)"), &rt9, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  372. memDC.DrawText(_T("请假(分)"), &rt10, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  373. memDC.MoveTo(rt1.right, rt1.top);
  374. memDC.LineTo(rt1.right, rt1.bottom);
  375. memDC.MoveTo(rt2.right, rt1.top);
  376. memDC.LineTo(rt2.right, rt1.bottom);
  377. memDC.MoveTo(rt3.right, rt1.top);
  378. memDC.LineTo(rt3.right, rt1.bottom);
  379. memDC.MoveTo(rt4.right, rt1.top);
  380. memDC.LineTo(rt4.right, rt1.bottom);
  381. memDC.MoveTo(rt5.right, rt1.top);
  382. memDC.LineTo(rt5.right, rt1.bottom);
  383. memDC.MoveTo(rt6.right, rt1.top);
  384. memDC.LineTo(rt6.right, rt1.bottom);
  385. memDC.MoveTo(rt7.right, rt1.top);
  386. memDC.LineTo(rt7.right, rt1.bottom);
  387. memDC.MoveTo(rt8.right, rt1.top);
  388. memDC.LineTo(rt8.right, rt1.bottom);
  389. memDC.MoveTo(rt9.right, rt1.top);
  390. memDC.LineTo(rt9.right, rt1.bottom);
  391. memDC.MoveTo(rc.left, rt1.bottom);
  392. memDC.LineTo(rc.right, rt1.bottom);
  393. CString strID, strName, strDate, strSID, strTime, strAttTime, strLate, strEarlier, strAbsent, strLeave;
  394. rc.SetRect(nLeft, nTop+fAdd, nRight, nTop+2*fAdd);
  395. rt1.SetRect(nLeft+nTextAdd, rc.top, rc.right-12.2*nItemWide, rc.bottom);
  396. rt2.SetRect(rt1.right+nTextAdd, rt1.top, rt1.right + 1.5*nItemWide, rt1.bottom);
  397. rt3.SetRect(rt2.right+nTextAdd, rt1.top, rt2.right + 1.5*nItemWide, rt1.bottom);
  398. rt4.SetRect(rt3.right+nTextAdd, rt1.top, rt3.right + 2*nItemWide, rt1.bottom);
  399. rt5.SetRect(rt4.right+nTextAdd, rt1.top, rt4.right + 1.6*nItemWide, rt1.bottom);
  400. rt6.SetRect(rt5.right+nTextAdd, rt1.top, rt5.right + 1.6*nItemWide, rt1.bottom);
  401. rt7.SetRect(rt6.right+nTextAdd, rt1.top, rt6.right + nItemWide, rt1.bottom);
  402. rt8.SetRect(rt7.right+nTextAdd, rt1.top, rt7.right + nItemWide, rt1.bottom);
  403. rt9.SetRect(rt8.right+nTextAdd, rt1.top, rt8.right + nItemWide, rt1.bottom);
  404. rt10.SetRect(rt9.right+nTextAdd, rt1.top, rc.right, rt1.bottom);
  405. int nCountItem = pGridCtrl->GetRowCount();
  406. for(int i=1;i<nItem; i++)
  407. {
  408. strID = pGridCtrl->GetItemText(i+iStart, 1);
  409. strName = pGridCtrl->GetItemText(i+iStart, 2);
  410. strDate = pGridCtrl->GetItemText(i+iStart, 3);
  411. strSID = pGridCtrl->GetItemText(i+iStart, 4);
  412. strTime = pGridCtrl->GetItemText(i+iStart, 5);
  413. strAttTime = pGridCtrl->GetItemText(i+iStart, 6);
  414. strLate = pGridCtrl->GetItemText(i+iStart, 7);
  415. strEarlier = pGridCtrl->GetItemText(i+iStart, 8);
  416. strAbsent = pGridCtrl->GetItemText(i+iStart, 9);
  417. strLeave = pGridCtrl->GetItemText(i+iStart, 10);
  418. memDC.DrawText(strID, &rt1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  419. memDC.DrawText(strName, &rt2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  420. memDC.DrawText(strDate, &rt3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  421. memDC.DrawText(strSID, &rt4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  422. memDC.DrawText(strTime, &rt5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  423. memDC.DrawText(strAttTime, &rt6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  424. memDC.DrawText(strLate, &rt7, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  425. memDC.DrawText(strEarlier, &rt8, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  426. memDC.DrawText(strAbsent, &rt9, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  427. memDC.DrawText(strLeave, &rt10, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  428. //下横线
  429. memDC.MoveTo(rc.left, rc.bottom);
  430. memDC.LineTo(rc.right, rc.bottom);
  431. memDC.MoveTo(rt1.right, rt1.top);
  432. memDC.LineTo(rt1.right, rt1.bottom);
  433. memDC.MoveTo(rt2.right, rt1.top);
  434. memDC.LineTo(rt2.right, rt1.bottom);
  435. memDC.MoveTo(rt3.right, rt1.top);
  436. memDC.LineTo(rt3.right, rt1.bottom);
  437. memDC.MoveTo(rt4.right, rt1.top);
  438. memDC.LineTo(rt4.right, rt1.bottom);
  439. memDC.MoveTo(rt5.right, rt1.top);
  440. memDC.LineTo(rt5.right, rt1.bottom);
  441. memDC.MoveTo(rt6.right, rt1.top);
  442. memDC.LineTo(rt6.right, rt1.bottom);
  443. memDC.MoveTo(rt7.right, rt1.top);
  444. memDC.LineTo(rt7.right, rt1.bottom);
  445. memDC.MoveTo(rt8.right, rt1.top);
  446. memDC.LineTo(rt8.right, rt1.bottom);
  447. memDC.MoveTo(rt9.right, rt1.top);
  448. memDC.LineTo(rt9.right, rt1.bottom);
  449. memDC.MoveTo(rc.left, rt1.bottom);
  450. memDC.LineTo(rc.right, rt1.bottom);
  451. rc.top += fAdd;
  452. rc.bottom += fAdd;
  453. rt1.top = rc.top;
  454. rt1.bottom = rc.bottom;
  455. rt2.top = rt1.top;
  456. rt2.bottom = rt1.bottom;
  457. rt3.top = rt1.top;
  458. rt3.bottom = rt1.bottom;
  459. rt4.top = rt1.top;
  460. rt4.bottom = rt1.bottom;
  461. rt5.top = rt1.top;
  462. rt5.bottom = rt1.bottom;
  463. rt6.top = rt1.top;
  464. rt6.bottom = rt1.bottom;
  465. rt7.top = rt1.top;
  466. rt7.bottom = rt1.bottom;
  467. rt8.top = rt1.top;
  468. rt8.bottom = rt1.bottom;
  469. rt9.top = rt1.top;
  470. rt9.bottom = rt1.bottom;
  471. rt10.top = rt1.top;
  472. rt10.bottom = rt1.bottom;
  473. if((i+iStart+1)>=nCountItem)
  474. break;
  475. }
  476. //结尾
  477. memDC.MoveTo(rc.left, nTop);
  478. memDC.LineTo(rc.left, rc.top);
  479. memDC.MoveTo(rc.right, nTop);
  480. memDC.LineTo(rc.right, rc.top);
  481. memDC.DrawText(csLFinality, &rc, DT_LEFT| DT_VCENTER | DT_SINGLELINE);
  482. memDC.DrawText(csRFinality, &rc, DT_RIGHT| DT_VCENTER | DT_SINGLELINE);
  483. memDC.SelectObject(oldfont);
  484. memDC.SelectObject(hPenOld);
  485. }
  486. TitleFont.DeleteObject();
  487. DetailFont.DeleteObject();
  488. cPen.DeleteObject();
  489. }

vc 实现打印功能的更多相关文章

  1. vc下打印透明背景图片

    一.前言 刚接到个任务,要把带有透明背景的章子图片打印出来,开始觉得不是很简单吗,直接用vc自动生成的打印功能不就ok了.不过问题却不是想像的那么简单! 二.窗口中显示透明图片 在窗口中显示图片,可以 ...

  2. MFC 实现打印机打印功能

    Visual C++6.0是开发Windows应用程序的强大工具,但是要通过它实现程序的打印功能,一直是初学者的一个难点,经常有朋友询问如何在VC中实现打印功能,他们往往感到在MFC提供的框架内实现这 ...

  3. jQuery:实现网页的打印功能

    实现的打印功能大致跟浏览器的 Ctrl+P 效果一样 一.直接上代码 <!DOCTYPE html> <head> <meta charset="utf-8&q ...

  4. C#程序调用CodeSoft预先设计好的标签模块实现打印功能

    if (this.tbSetLabel.Text.Trim() == "") { MessageBox.Show("请先 Enter 选择标签模板文件!", & ...

  5. 完美演绎DevExpress XtraPrinting Library 的打印功能

    完美演绎DevExpress XtraPrinting Library 的打印功能 2010-05-14 17:40:49|  分类: 默认分类|字号 订阅     设计报告不仅费时间,而且还乏味!但 ...

  6. web页面实现指定区域打印功能

    web页面实现指定区域打印功能 使用CSS,定义一个.noprint的class,将不打印的内容放入这个class内. 详细如下: <style media=print type="t ...

  7. 开源的javascript实现页面打印功能,兼容所有的浏览器(情况属实)

    这篇文章完全是属于技术文章,也是记录一下自己在项目当中遇到的坑爹问题啊,因为是B/S的程序,所以打印功能还是必须要有的,对于打印我选择了一个js插件,发现非常的简单和方便,所以这里拿出来和大家分享一下 ...

  8. IE下实现打印功能

    先贴代码: <html> <head> <style type="text/css"> *{margin:0px;padding:0px;} . ...

  9. DevExpress打印功能 z

    一.打印功能说明: 打印功能,我们有多种实现方式,可以根据需要自行选择,我简单的总结下两种方法. (1).使用微软.net框架自带的PrintDocument,这种方式是直接借助Graphics,自行 ...

随机推荐

  1. Zabbix配置文件详解之服务端zabbix_server

    zabbix作为运维邻域不可缺少的一员,它的各种文档可是数不胜数啊,但是关于配置文件的解释与说明就有点少.这里列出zabbix配置文件篇之zabbix_server. Zabbix Server端配置 ...

  2. 2.Unable to instantiate Action, templateAction, defined for 'template_list' in namespace '/'templateAction

    1.错误说没有命名空间'templateAction,但是在struts里写了这个,名字跟Action的名字是一样的,为什么会报这个错误 2.反复检查路径和名字,都没有问题 3.发现没有对其进行注入操 ...

  3. 编译jsoncpp库以及要注意的问题

    原创文章,转载请注明原作者与本文原始URL. 版本:jsoncpp-src-0.5.0.zip简介:jsoncpp是用cpp实现的json库,可以拼装,解析,生成json串.我们要把他编译成动态库.这 ...

  4. 小程序 - c字符串表示大整数

    #define max(a, b) ((a) > (b) ? (a) : (b)) static char* reverse(char *str) { char *l, *r, c; ; l & ...

  5. JAVA对象转化JSON出现死循环问题

    主要是解决JSON因Hibernate映射生成的集合的转化出现的死循环问题. 这个方法很重要 public String ajaxJsonByObjectDirecdt(Object obj, Str ...

  6. 解决代码着色组件SyntaxHighlighter行号显示问题

    SyntaxHighlighter是根据代码中的换行符分配行号的.但是,如果一行代码或者注释比较长,在页面显示时需要分成多行显示,这时行号就对不上了.如下图: 通过下面的css强制不换行,可以避开这个 ...

  7. Reading Notes of Acceptance Test Engineering Guide

    The Acceptance Test Engineering Guide will provide guidance for technology stakeholders (developers, ...

  8. Visual Studio 2013 新功能 Memory Dump 分析器

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. TechEd2013 发现新功能 12月5日和6日,在国家会议中心参加了微软的 TechEd2013 ...

  9. A memory leak issue with WPF Command Binding

    Background In our application, we have a screen which hosts several tabs. In each tab, it contains a ...

  10. UTL_FILE建文件失败“ORA-29280: 目录路径无效”错误

    存储过程写文件需要配置可写的目录,具体是utl_file_dir这个参数,把UTL_FILE输出的目录写到这个参数,如果不限制,可以令utl_file_dir=*   查看:   SQL> sh ...