MFC 列印相關操作,mfc列印相關
雖說現在已經有越來越多的人轉向用C#來做介面的開發,但是對於一個習慣了C++這種半物件導向語言的人來說,MFC依然是難割捨的存在。最近在做些資料庫相關的事,因為是資料庫,自然離不開列印報表之類的東西,所以順帶的也去研究了下如何用MFC來進行列印相關的的操作。
本篇文章參考的比較多的是這篇文章和MSDN的範例程式碼,另外這篇文章也提供了很多有用的參考,如果想看原文的話可以去看看。
直接用微軟提供的CPrintDialog類進行列印的相關操作是非常簡單的,本人將代碼封裝成為兩個函數,除了實際往一頁紙上繪製東西的部分在第二個函數中進行定義外,其他與列印相關的操作都在第一個函數上實現了。具體如下:
列印相關操作主函數:
void CPrinttToPrinterDlg::OnBnClickedButtonPrint(){CPrintDialog dlg(FALSE, PD_ALLPAGES, NULL);//列印對話方塊對象定義,參數一設定彈出對話方塊為列印對話方塊,參數二設定列印範圍為全部頁面,參數三可指定印表機,這裡預設即可/*列印對話方塊的初始值設定,在實際應用中可根據需要進行設定,如通過預先計算得到要列印的頁面範圍等*/dlg.m_pd.nMinPage = 1;//指定開始/結束頁碼編輯控制項的頁碼範圍的最小值,若nMinPage=nMaxPage,則“頁碼範圍”單選鈕和開始/結束頁碼編輯控制項被灰化dlg.m_pd.nMaxPage = 2;//指定開始/結束頁碼編輯控制項的頁碼範圍的最大值dlg.m_pd.nCopies = 1;//指定拷貝份數編輯控制項的初始值dlg.m_pd.nFromPage = 1;//指定開始頁碼編輯控制項的初始值dlg.m_pd.nToPage = 2;//指定結束頁碼編輯控制項的初始值if (dlg.DoModal() == IDOK){HDC hdcPrinter = dlg.GetPrinterDC();if (hdcPrinter == NULL)//檢取裝置環境的控制代碼,檢索不到則提醒並退出{MessageBox(_T("Buy a printer!"));}else{/*建立圖形裝置環境並與印表機裝置關聯,在上面繪圖就相當於往印表機要打出的紙上繪圖*/CDC dcPrinter;dcPrinter.Attach(hdcPrinter);/* *在列印設定過程中有些東西我們希望使用者來選,所以使用了對話方塊的形式,但是有些 *東西比如紙張大小和方向等我們希望它是固定的,不能讓使用者隨意設定造成麻煩 *因此,我們利用已經得到的印表機圖形裝置環境,通過修改它來實現固定設定的功能 */LPDEVMODE pDevMode;pDevMode = (LPDEVMODE)GlobalLock(dlg.m_pd.hDevMode);pDevMode->dmOrientation = DMORIENT_LANDSCAPE;//設定方向為橫向pDevMode->dmPaperSize = DMPAPER_A4;//設定紙張大小為A4dcPrinter.ResetDC(pDevMode);//通知印表機驅動程式接收列印文檔並開始列印DOCINFO docinfo;memset(&docinfo, 0, sizeof(docinfo));docinfo.cbSize = sizeof(docinfo);docinfo.lpszDocName = _T("CDC::StartDoc() Code Fragment");//如果初始化失敗則提醒並退出if (dcPrinter.StartDoc(&docinfo) < 0){MessageBox(_T("Printer wouldn't initalize"));}else{/*列印的紙張大小我們是需要知道的,此外我們還需要裝置像素點和實際長度單位的換算關係即DPI*/int xDPI = GetDeviceCaps(hdcPrinter, LOGPIXELSX);//返回X方向上每英寸的裝置點數,即DPIfloat mmdpix = xDPI / 25.4;//每毫米所佔的裝置點數int yDPI = GetDeviceCaps(hdcPrinter, LOGPIXELSY);//返回Y方向上每英寸的裝置點數,即DPIfloat mmdpiy = yDPI / 25.4;//每毫米所佔的裝置點數float printerscreenx, printerscreeny;//這裡得到印表機螢幕的寬高,也就是紙張的大小,會比實際小約6mmprinterscreenx = GetDeviceCaps(hdcPrinter, HORZSIZE);printerscreeny = GetDeviceCaps(hdcPrinter, VERTSIZE);/*因為要列印的頁碼範圍和份數是使用者選擇的,所以在此對使用者選擇的項做處理*/int pagebegin, pageend;//列印範圍if (dlg.PrintAll())//看使用者是否選擇了全部列印這一項,是的話則全部列印{pagebegin = dlg.m_pd.nMinPage;pageend = dlg.m_pd.nMaxPage;}else if (dlg.PrintRange())//使用者選擇了選定頁碼範圍項{pagebegin = dlg.m_pd.nFromPage;pageend = dlg.m_pd.nToPage;}else//使用者選擇了選定範圍列印,因為我們在這裡沒有提供選定範圍的功能,所以使用者一旦選擇這裡當成是操作錯誤處理即可{MessageBox(_T("Could not choise this one"));dcPrinter.AbortDoc();//錯誤退出區別於EndDoc}int ncopy = dlg.m_pd.nCopies;//使用者選擇列印分數/*在這裡進行列印工作*/while (ncopy--)//逐份列印{for (int page = pagebegin; page <= pageend; page++)//從選定範圍開始列印{if (dcPrinter.StartPage() < 0){MessageBox(_T("Could not start page"));dcPrinter.AbortDoc();//錯誤退出區別於EndDoc}else//如果進入這裡則繪出要列印內容並結束掉一頁的列印{doThePrint(dcPrinter, page, mmdpix, mmdpiy, printerscreenx, printerscreeny);dcPrinter.EndPage();}}}}dcPrinter.EndDoc();//列印完成退出dcPrinter.Detach();//釋放DC}}}
實際往一頁紙上列印的內容在此函數中進行定義,下面函數內容實現在列印的紙上繪製一個大小稍小於頁面的綠色矩形:
void CPrinttToPrinterDlg::doThePrint(CDC &dc,int page, float mdpix, float mdpiy, float mpagex, float mpagey)//列印實際繪圖函數,往參數一傳入的CDC上面繪圖{CPen pen, *pOldPen;// 定義筆對象和指標 // 建立10單位寬的綠色實心筆 pen.CreatePen(PS_SOLID, 100, RGB(0, 255, 0));pOldPen = dc.SelectObject(&pen);// 選入綠色筆 dc.Rectangle(0 * mdpix, 0 * mdpiy, mpagex*mdpix, mpagey*mdpiy);// 畫矩形 dc.SelectObject(pOldPen);// 選出綠色筆 pen.DeleteObject();// 刪除綠色筆}
到此文章就已經寫得七七八八了,調用主函數就可以實現往印表機上列印動東西的功能。至於列印什麼東西,如何去打,就是GDI繪圖的事了。另外由於我們還沒有實現預覽列印的功能,所以可以用虛擬印表機來看效果,當然如果有錢,也可以直接用真的印表機來看啦哈哈,本人用的是finepring,簡而言之就兩個字形容,神器!
預覽列印還有如何去列印資料表格這些功能本人後面如果研究實現了的話也會貼上來,或者發個連結上來,這篇文章就先到這裡吧。