首页 > 代码库 > vc 实现打印功能

vc 实现打印功能

 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、添加代码,编译运行程序。

 

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

在打印预览对话框类中

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


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

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



vc 实现打印功能