多页打印

来源:互联网 发布:怎么样自学编程 编辑:程序博客网 时间:2024/05/29 08:40

搜了N久,找到这么一篇文章:使用RichEdit打印http://www.codeproject.com/KB/printing/richeditprint.aspx?fid=13948&fr=1#xx0xx 打印总算完成了. 但是也诚如文章开头所说:

The preview is sucks!

 

这是取自另外一篇文章的代码,我做了一些修改:

[cpp] view plaincopy
  1. BOOL PrintRich(CRichEditCtrl *pCtrl ,const CString& Title)  
  2. {  
  3.     CDC ThePrintDC; //create a device context to use  
  4.     CPrintDialog PrintDialog(FALSE);  //make a print dialog too  
  5.     if(PrintDialog.DoModal( ) == IDOK) //pressed the ok button on the print dialog?  
  6.     {  
  7.         ThePrintDC.Attach(PrintDialog.GetPrinterDC());//if so get settings  
  8.     }  
  9.     else  
  10.     {  
  11.         return FALSE; //leave this procedure, before anything bad happens  
  12.     }  
  13.     DOCINFO di; //make a docinfo structure  
  14.     ::ZeroMemory(&di, sizeof(DOCINFO));  
  15.     di.cbSize = sizeof(DOCINFO);     //set size member  
  16.     di.lpszDocName = Title;//set doc name, was passed via another funtion  
  17.     FORMATRANGE fr;  //format range structure  
  18.     ::ZeroMemory(&fr, sizeof(FORMATRANGE));  
  19.     HDC hdc = ThePrintDC.GetSafeHdc();        //get handle to DC we are using  
  20.     fr.hdc = hdc;                                            //Set meber in FormatRange struct  
  21.     fr.hdcTarget = hdc;                //Set member in FormatRange struct  
  22.     //This bit here will get all the dimentions of the printer setup  
  23.     int nHorizRes = ThePrintDC.GetDeviceCaps(HORZRES),                 //width P in MM  
  24.         nVertRes = ThePrintDC.GetDeviceCaps(VERTRES),        //hight in raster lines  
  25.         nLogPixelsX = ThePrintDC.GetDeviceCaps(LOGPIXELSX),  //pixels per inch along x  
  26.         nLogPixelsY = ThePrintDC.GetDeviceCaps(LOGPIXELSY);  //pixels per inch along y  
  27.     //set the printable area of printer in the FormatRange struct  
  28.     fr.rcPage.left = 0; //these 2 mean top left  
  29.     fr.rcPage.top = 0;  
  30.     fr.rcPage.right    = (nHorizRes * 1440 / nLogPixelsX);//these 2 mean bottom right  
  31.     fr.rcPage.bottom   = (nVertRes  * 1440 / nLogPixelsY);    //equation changes pixel to TWIPS  
  32.     // Set up some margins all around. Make them one inch  
  33.     //results vary on printers depending on setup  
  34.     fr.rc.left   = fr.rcPage.left + 1100;  // 1440 TWIPS = 1 inch.  
  35.     fr.rc.top    = fr.rcPage.top + 1440;  
  36.     fr.rc.right  = fr.rcPage.right - 1100;  
  37.     fr.rc.bottom = fr.rcPage.bottom - 1440;  
  38.     //select all text for printing  
  39.     CHARRANGE &cr = fr.chrg;  
  40.     cr.cpMin=0;  
  41.     cr.cpMax=-1;//-1 selects all  
  42.     //get length of document, used for more than one page  
  43.     long CharRange = pCtrl->GetTextLength();;  
  44.     int ErrorStatus=0;  
  45.     //Start Printing  
  46.     //ThePrintDC.SetAbortProc(&AbortProc(hdc, )); //dont know how callbacks works yet  
  47.     ThePrintDC.StartDoc(&di); //start printing document  
  48.     long LastChar = -1;//will store document length  
  49.     do  
  50.     {  
  51.         ThePrintDC.StartPage(); //start the page  
  52.         cr.cpMin = LastChar + 1;//Change charrange struct for next page  
  53.         cr.cpMax = -1;  
  54.         LastChar = pCtrl->FormatRange( &fr, TRUE );//send text to DC, and record index  
  55.         //of last fitting char  
  56.         ErrorStatus=ThePrintDC.EndPage();   //end this page, and record status  
  57.         if (cr.cpMin >= LastChar)  
  58.             break;  
  59.         cr.cpMin = LastChar;  
  60.         cr.cpMax = CharRange; //using last char printed  
  61.     }while(LastChar < CharRange && ErrorStatus > 0); //while there is stuff to print out there  
  62.     //is not an error(error is -No)  
  63.     //if there is an error or printing has finished  
  64.     //have to make sure AbortDoc is called instead of EndDoc if there has been a problem  
  65.     //  delete pDlg;  
  66.     CRect rcClient;  
  67.     pCtrl->GetClientRect(&rcClient);  
  68.     pCtrl->DisplayBand(&rcClient);  
  69.     switch(ErrorStatus)  
  70.     {  
  71.     case SP_ERROR:  
  72.         {  
  73.             ThePrintDC.AbortDoc();  
  74.             AfxMessageBox(_T("There was a general printing error, please check printer is working properly, connected, on line etc."), MB_OK | MB_ICONEXCLAMATION);  
  75.             return FALSE;  
  76.         }  
  77.     case SP_APPABORT:  
  78.         {  
  79.             ThePrintDC.AbortDoc();  
  80.             return FALSE;  
  81.         }  
  82.     case SP_USERABORT:  
  83.         {  
  84.             ThePrintDC.AbortDoc();  
  85.             return FALSE;  
  86.         }  
  87.     case SP_OUTOFDISK:  
  88.         {  
  89.             ThePrintDC.AbortDoc();  
  90.             AfxMessageBox(_T("out of disk"));  
  91.             return FALSE;  
  92.         }  
  93.     case SP_OUTOFMEMORY:  
  94.         {  
  95.             ThePrintDC.AbortDoc();  
  96.             AfxMessageBox(_T("out of memeory"));  
  97.             return FALSE;  
  98.         }  
  99.     default:  
  100.         {  
  101.             ThePrintDC.EndDoc();  
  102.             return TRUE;  
  103.         }  
  104.     }  
  105. }  
 

 

只此一个函数,即可完成多页打印功能,而你只需要提供一个RichEdit控件的指针即可.

但是在实际测试的过程中却总有问题:

[cpp] view plaincopy
  1. do  
  2. {  
  3.     ThePrintDC.StartPage();  
  4.     ...  
  5.         LastChar = pCtrl->FormatRange( &fr, TRUE );  
  6.     // LastChar 达不到 CharRange的值  
  7.     ...  
  8.         ErrorStatus=ThePrintDC.EndPage();  
  9. }while(LastChar < CharRange && ErrorStatus > 0);   
 

LastChar 达不到 CharRange的值,但是当我加上这么一行代码,文档也能完全打印出来(参见上面函数完整代码):

 

[cpp] view plaincopy
  1. if (cr.cpMin >= LastChar)  
  2.     break;  
 

 

这是什么道理咩??UNICODE字符集问题咩?

从RichEdit20W它就已经支持UNICODE了. 但是在某些方面它又表现的不支持UNICODE,比如StreamIn

[cpp] view plaincopy
  1. void CAutoRichEditCtrl::SetRTF(CString sRTF)  
  2. {  
  3.     // Put the RTF string sRTF into the rich edit control.  
  4.     // Read the text in  
  5.     EDITSTREAM es;  
  6.     es.dwError = 0;  
  7.     es.pfnCallback = CBStreamIn;  
  8.     es.dwCookie = (DWORD) &sRTF;  
  9.     StreamIn(SF_RTF, es);   // Do it.  
  10.       
  11. }  
  12. /* 
  13.     Callback function to stream an RTF string into the rich edit control. 
  14. */  
  15. DWORD CALLBACK CAutoRichEditCtrl::CBStreamIn(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)  
  16. {  
  17.     // We insert the rich text here.  
  18. /*   
  19.     This function taken from CodeGuru.com 
  20.     http://www.codeguru.com/richedit/rtf_string_streamin.shtml 
  21.     Zafir Anjum 
  22. */  
  23.     CString *pstr = (CString *) dwCookie;  
  24.     if (pstr->GetLength() < cb)  
  25.     {  
  26.         *pcb = pstr->GetLength();  
  27.         memcpy(pbBuff, (LPCSTR) *pstr, *pcb);  
  28.         pstr->Empty();  
  29.     }  
  30.     else  
  31.     {  
  32.         *pcb = cb;  
  33.         memcpy(pbBuff, (LPCSTR) *pstr, *pcb);  
  34.         *pstr = pstr->Right(pstr->GetLength() - cb);  
  35.     }  
  36.     return 0;  
  37. }  
 

 

这两个函数在使用多字节字符集编译的工程中表现良好,但是在UNICODE字符集下就会出现乱码

向下面一样,将字符串转换一下后则运行无误

 

[c-sharp] view plaincopy
  1. void CAutoRichEditCtrl::SetRTF(CString sRTF)  
  2. {  
  3.     // Put the RTF string sRTF into the rich edit control.  
  4.     // Read the text in  
  5.     EDITSTREAM es;  
  6.     es.dwError = 0;  
  7.     es.pfnCallback = CBStreamIn;  
  8. // fixed by qiuchengw -- unicode is not right  
  9.     CAnsi ansi(sRTF);  
  10.     std::string str(ansi);  
  11.     es.dwCookie = (DWORD)&str;  
  12. //  es.dwCookie = (DWORD) &sRTF;  
  13.     StreamIn(SF_RTF, es);   // Do it.  
  14.       
  15. }  
  16. /* 
  17.     Callback function to stream an RTF string into the rich edit control. 
  18. */  
  19. DWORD CALLBACK CAutoRichEditCtrl::CBStreamIn(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)  
  20. {  
  21.     // We insert the rich text here.  
  22. /*   
  23.     This function taken from CodeGuru.com 
  24.     http://www.codeguru.com/richedit/rtf_string_streamin.shtml 
  25.     Zafir Anjum 
  26. */  
  27.     std::string *pstr = (std::string *)dwCookie;  
  28. //  CString *pstr = (CString *) dwCookie;  
  29.     int len = pstr->length();  
  30.     if (len < cb)  
  31.     {  
  32.         *pcb = len;  
  33.         memcpy(pbBuff,pstr->c_str(),len);  
  34.         pstr->clear();  
  35.     }  
  36.     else  
  37.     {  
  38.         *pcb = cb;  
  39.         memcpy(pbBuff,pstr->c_str(),cb);  
  40.         *pstr = pstr->substr(cb);  
  41.     }  
  42. /*  if (pstr->GetLength() < cb) 
  43.     { 
  44.         *pcb = pstr->GetLength(); 
  45.         memcpy(pbBuff, (LPCSTR) *pstr, *pcb); 
  46.         pstr->Empty(); 
  47.     } 
  48.     else 
  49.     { 
  50.         *pcb = cb; 
  51.         memcpy(pbBuff, (LPCSTR) *pstr, *pcb); 
  52.         *pstr = pstr->Right(pstr->GetLength() - cb); 
  53.     } 
  54. */  
  55.     return 0;  
  56. }  
 

 

最近比较忙, 没有做什么更多测试,也不深入研究了,下面的两个问题,烦请高人解决:

1. 是否StreamIn真的不支持UNICODE,还是我某些设置没有做好(比如在StreamIn之前应该做什么初始化之类的)?

2. 那个打印是否也真的是UNICODE的问题? 有更优雅的解决方法不?  我那个"解决方法"太暴力, 简直成了我一块心病啊!

原创粉丝点击