MFC
打印程序的編制
MFC
在實(shí)現(xiàn)打印編程工作時(shí)已經(jīng)建立了一個(gè)已有的框架,我們只要往這個(gè)框架里面填東西即可。
打印工作其實(shí)就是在
DC
上繪圖,不過(guò)這里的
DC
是打印機(jī)的
DC
,明確這一點(diǎn)之后,想當(dāng)然的,我們打印的任務(wù)可以分為獲取打印機(jī)
DC
、根據(jù)打印機(jī)驅(qū)動(dòng)讓用戶(hù)交互設(shè)置打印參數(shù)、開(kāi)始打印、打印的具體過(guò)程(分頁(yè)、繪制等)、結(jié)束打印、釋放
DC
。以下通過(guò)一段示列代碼來(lái)說(shuō)明:
//
打印控制函數(shù)
void print()
{
?????? CPrintDialog dlg(FALSE,PD_ALLPAGES);//
如為
TRUE
則不能實(shí)現(xiàn)打印功能,
//
而是建立打印機(jī),祥查
msdn
?????? // Get the default printer.
?????? dlg.m_pd.nMinPage = 1;
?????? dlg.m_pd.nMaxPage = 15;
?????? dlg.m_pd.nCopies = 1;
?????? dlg.m_pd.nFromPage = 1;
?????? dlg.m_pd.nToPage = 2;
?????? if (dlg.DoModal() == IDOK)
?????? {//
如果僅打印一份則可以用
dlg.GetDefaults();
????????????? HDC hdcPrinter = dlg.GetPrinterDC();
????????????? if (hdcPrinter == NULL) // Is a default printer set up?
????????????? {
???????????????????? AfxMessageBox(_T("Buy a printer!"));
????????????? }
????????????? else
????????????? {
???????????????????? CDC dcPrinter;
???????????????????? dcPrinter.Attach(hdcPrinter);
???????????????????? //
通知打印機(jī)驅(qū)動(dòng)程序接受打印文檔
???????????????????? DOCINFO docinfo;
???????????????????? memset(&docinfo, 0, sizeof(docinfo));
???????????????????? docinfo.cbSize = sizeof(docinfo);
???????????????????? docinfo.lpszDocName = _T("CDC::StartDoc() Code Fragment");
???????????????????? DEVMODE * dm = dlg.GetDevMode();
???????????????????? float rato = dm->dmPrintQuality / 25.4;//
轉(zhuǎn)化到
mm
模式下
???????????????????? // If it fails, complain and exit gracefully.
???????????????????? if (dcPrinter.StartDoc(&docinfo) < 0)
???????????????????? {
??????????????????????????? AfxMessageBox(_T("Printer would not initalize"));
???????????????????? }
???????????????????? else
???????????????????? {
??????????????????????????? // Do printing.
??????????????????????????? BOOL bPrintOK = TRUE;
??????????????????????????? int m_nCopies = dlg.m_pd.nCopies;
??????????????????????????? int page_Min(0),page_Max(0);
??????????????????????????? if (m_nCopies > 1)
??????????????????????????? {
?????????????????????????????????? //
是否逐份打印
?????????????????????????????????? if (dlg.PrintCollate() == TRUE)
?????????????????????????????????? {
????????????????????????????????????????? //
是否全部打印
????????????????????????????????????????? if (dlg.PrintAll() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
全部打印
???????????????????????????????????????????????? page_Min = dlg.m_pd.nMinPage;
???????????????????????????????????????????????? page_Max = dlg.m_pd.nMaxPage;
????????????????????????????????????????? }
????????????????????????????????????????? else if (dlg.PrintRange() == TRUE)
????????????????????????????????????????? {
??????
????????????????????????????????????????? //
選定頁(yè)碼范圍
???????????????????????????????????????????????? page_Min = dlg.m_pd.nFromPage;
???????????????????????????????????????????????? page_Max = dlg.m_pd.nToPage;
????????????????????????????????????????? }
????????????????????????????????????????? else if (dlg.PrintSelection() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
選定的選擇區(qū)域
???????????????????????????????????????????????? //
暫時(shí)不知道怎么處理的
????????????????????????????????????????? }
????????????????????????????????????????? for(int i = 0; i < m_nCopies; i++)
????????????????????????????????????????? {
???????????????????????????????????????????????? for(UINT j = page_Min; j < page_Max + 1; j++)
???????????????????????????????????????????????? {
??????????????????????????????????????????????????????? if (dcPrinter.StartPage() < 0)//
只起到判斷作用,不
//
加不會(huì)影響正常打印
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? AfxMessageBox(_T("Could not start page"));
?????????????????????????????????????????????????????????????? bPrintOK = FALSE;
?????????????????????????????????????????????????????????????? break;
??????????????????????????????????????????????????????? }????????????????????????????????
??????????????????????????????????????????????????????? OnPrint(dcPrinter, j, rato);
??????????????????????????????????????????????????????? if (dcPrinter.EndPage() <= 0)? //
告訴打印驅(qū)動(dòng)換
//
頁(yè),如果不加則將所有頁(yè)打在一張紙上
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? AfxMessageBox(_T("Could not end page"));
?????????????????????????????????????????????????????????????? bPrintOK = FALSE;
?????????????????????????????????????????????????????????????? break;
??????????????????????????????????????????????????????? }
???????????????????????????????????????????????? }
???????????????????????????????????????????????? if (bPrintOK == FALSE)
???????????????????????????????????????????????? {
??????????????????????????????????????????????????????? dcPrinter.AbortDoc();
??????????????????????????????????????????????????????? break;
???????????????????????????????????????????????? }
????????????????????????????????????????? }
?????????????????????????????????? }
?????????????????????????????????? else
?????????????????????????????????? {
????????????????????????????????????????? //
是否全部打印
????????????????????????????????????????? if (dlg.PrintAll() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
全部打印
???????????????????????????????????????????????? page_Min = dlg.m_pd.nMinPage;
???????????????????????????????????????????????? page_Max = dlg.m_pd.nMaxPage;
????????????????????????????????????????? }
????????????????????????????????????????? else if (dlg.PrintRange() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
選定頁(yè)碼范圍
???????????????????????????????????????????????? page_Min = dlg.m_pd.nFromPage;
???????????????????????????????????????????????? page_Max = dlg.m_pd.nToPage;
????????????????????????????????????????? }
????????????????????????????????????????? else if (dlg.PrintSelection() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
選定的選擇區(qū)域
???????????????????????????????????????????????? //
暫時(shí)不知道怎么處理的
????????????????????????????????????????? }
????????????????????????????????????????? for(UINT j = page_Min; j < page_Max + 1; j++)
????????????????????????????????????????? {
???????????????????????????????????????????????? for(int i = 0; i < m_nCopies; i++)
???????????????????????????????????????????????? {
??????????????????????????????????????????????????????? if (dcPrinter.StartPage() < 0)//
只起到判斷作用,不
//
加不會(huì)影響正常打印
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? AfxMessageBox(_T("Could not start page"));
?????????????????????????????????????????????????????????????? bPrintOK = FALSE;
?????????????????????????????????????????????????????????????? break;
??????????????????????????????????????????????????????? }????????????????????????????????
????????????????????????????????????????????????
?????? OnPrint(dcPrinter, j, rato);
??????????????????????????????????????????????????????? if (dcPrinter.EndPage() <= 0)? //
告訴打印驅(qū)動(dòng)換
//
頁(yè),如果不加則將所有頁(yè)打在一張紙上
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? AfxMessageBox(_T("Could not end page"));
?????????????????????????????????????????????????????????????? bPrintOK = FALSE;
?????????????????????????????????????????????????????????????? break;
??????????????????????????????????????????????????????? }
???????????????????????????????????????????????? }
???????????????????????????????????????????????? if (bPrintOK == FALSE)
?????????????????????????????????????????
?????? {
??????????????????????????????????????????????????????? dcPrinter.AbortDoc();
??????????????????????????????????????????????????????? break;
???????????????????????????????????????????????? }
????????????????????????????????????????? }
?????????????????????????????????? }
??????????????????????????? }
??????????????????????????? else
??????????????????????????? {
?????????????????????????????????? //
是否全部打印
?????????????????????????????????? if (dlg.PrintAll() == TRUE)
?????????????????????????????????? {
????????????????????????????????????????? //
全部打印
????????????????????????????????????????? page_Min = dlg.m_pd.nMinPage;
????????????????????????????????????????? page_Max = dlg.m_pd.nMaxPage;
?????????????????????????????????? }
?????????????????????????????????? else if (dlg.PrintRange() == TRUE)
?????????????????????????????????? {
????????????????????????????????????????? //
選定頁(yè)碼范圍
????????????????????????????????????????? page_Min = dlg.m_pd.nFromPage;
????????????????????????????????????????? page_Max = dlg.m_pd.nToPage;
?????????????????????????????????? }
?????????????????????????????????? else if (dlg.PrintSelection() == TRUE)
?????????????????????????????????? {
????????????????????????????????????????? //
選定的選擇區(qū)域
????????????????????????????????????????? //
暫時(shí)不知道怎么處理的
?????????????????????????????????? }
?????????????????????????????????? for(UINT i = page_Min; i < page_Max + 1; i++)
?????????????????????????????????? {
????????????????????????????????????????? if (dcPrinter.StartPage() < 0)//
只起到判斷作用,不加不會(huì)
//
影響正常打印
????????????????????????????????????????? {
???????????????????????????????????????????????? AfxMessageBox(_T("Could not start page"));
???????????????????????????????????????????????? bPrintOK = FALSE;
dcPrinter.AbortDoc();
???????????????????????????????????????????????? break;
????????????????????????????????????????? }????????????????????????????????
????????????????????????????????????????? OnPrint(dcPrinter, i, rato);
????????????????????????????????????????? if (dcPrinter.EndPage() <= 0)//
告訴打印驅(qū)動(dòng)換頁(yè),如果不
//
加則將所有頁(yè)打在一張紙上
????????????????????????????????????????? {
???????????????????????????????????????????????? AfxMessageBox(_T("Could not end page"));
???????????????????????????????????????????????? bPrintOK = FALSE;
dcPrinter.AbortDoc();
???????????????????????????????????????????????? break;
????????????????????????????????????????? }
?????????????????????????????????? }
??????????????????????????? }
??????????????????????????? if (bPrintOK == TRUE)
??????????????????????????? {
?????????????????????????????????? dcPrinter.EndDoc();//
結(jié)束打印
?????????????
????????????? }
??????????????????????????? dcPrinter.Detach();//
釋放
DC
???????????????????? }???????????
????????????? }
?????? }????
}
?
//
具體的頁(yè)面繪制函數(shù)
void OnPrint(CDC &dc, UINT &nCurPage, float &rato)
{
?????? CFont font;
?????? font.CreatePointFont(100 * rato, "
宋體
");
?????? CGdiObject* pOldFont = dc.SelectObject(&font);
?????? CString str;
?????? str.Format("Hello World! -- %d",nCurPage);
?????? dc.TextOut(50 * rato, 50 * rato, str);
?????? dc.SelectObject(pOldFont);
}
?
以上打印過(guò)程沒(méi)有考慮打印預(yù)覽功能,只是實(shí)現(xiàn)直接打印功能,現(xiàn)在的虛擬打印機(jī)軟件(
pdffactory
)已經(jīng)很多了,個(gè)人感覺(jué)沒(méi)必要打印預(yù)覽功能。如果要要想實(shí)現(xiàn)打印預(yù)覽功能,那么我們就要考慮借用
MFC
的文檔-視圖結(jié)構(gòu)或者對(duì)話(huà)框結(jié)構(gòu),原理是一樣的。介紹此類(lèi)的文檔網(wǎng)絡(luò)上也很多,我剛開(kāi)始是看
http://www.vckbase.com/document/viewdoc/?id=1618
才打算寫(xiě)上面這么一篇的。后來(lái)發(fā)現(xiàn)
http://www.vckbase.com/document/viewdoc/?id=1270
,個(gè)人覺(jué)得很值得一讀的。
?
以下針對(duì)微軟封裝的幾個(gè)相應(yīng)函數(shù)按調(diào)用順序做一簡(jiǎn)單描述:
1.OnPreparePrinting
OnPreparePrinting
函數(shù)最先被調(diào)用,用來(lái)初始化打印機(jī)等。比如,若沒(méi)有安裝打印機(jī),則該函數(shù)將提示用戶(hù)安裝打印機(jī)。用戶(hù)程序可以向其中加入別的初始化代碼,比如,計(jì)算打印你的文檔所需要的總頁(yè)數(shù),然后調(diào)用視類(lèi)中的打印機(jī)初始化函數(shù)BOOL ? DoPreparePrinting(CPrintInfopInfo)即可。而用AppWizard生成的代碼中,OnPreparePrinting函數(shù)將只是調(diào)用函數(shù)DoPreparePrinting,并傳遞參數(shù)。
2.OnBeingPrinting
OnBeingPrinting
函數(shù)是開(kāi)始打印文檔前調(diào)用的函數(shù),用戶(hù)可以在其中加入另一些對(duì)于打印過(guò)程的初始化代碼,比如分配打印過(guò)程中將要使用的“筆”(CPen)、“刷子”(CBrush)等,默認(rèn)的代碼中該函數(shù)將直接返回。
3.OnPrepareDC
OnPrepareDC
函數(shù)用于在打印前準(zhǔn)備打印設(shè)備場(chǎng),如窗口大小、原點(diǎn),視圖大小、原點(diǎn)等。同時(shí)該函數(shù)在視類(lèi)顯示文檔內(nèi)容時(shí)也被調(diào)用,默認(rèn)的代碼中該函數(shù)調(diào)用基類(lèi)中的OnPrepareDC函數(shù)。
4.OnPrint
OnPrint
函數(shù)則是具體的打印過(guò)程,它利用前面準(zhǔn)備好的設(shè)備場(chǎng)進(jìn)行打印。
5.OnEndPrinting
OnEndPrinting
函數(shù)是與OnBeginPrinting函數(shù)相對(duì)應(yīng)的函數(shù),它在打印完成后由應(yīng)用框架調(diào)用,用于釋放在OnBeginPrinting中分配的“對(duì)象”,如“筆”、“刷子”等,其默認(rèn)的代碼中該函數(shù)將直接返回。
?
這幾個(gè)函數(shù)中,OnPreparePrinting、OnBeginPrinting、OnEndPrinting函數(shù)在一次打印過(guò)程中將只被調(diào)用一次,不管這一次打印內(nèi)容有多少頁(yè),而OnPrepareDC、OnPrint函數(shù)則每打印一頁(yè)都將被調(diào)用一次,這種調(diào)用次序?qū)τ诖蛴∈呛苡杏玫摹?span lang="EN-US">