MFC
打印程序的編制
MFC
在實現打印編程工作時已經建立了一個已有的框架,我們只要往這個框架里面填東西即可。
打印工作其實就是在
DC
上繪圖,不過這里的
DC
是打印機的
DC
,明確這一點之后,想當然的,我們打印的任務可以分為獲取打印機
DC
、根據打印機驅動讓用戶交互設置打印參數、開始打印、打印的具體過程(分頁、繪制等)、結束打印、釋放
DC
。以下通過一段示列代碼來說明:
//
打印控制函數
void print()
{
?????? CPrintDialog dlg(FALSE,PD_ALLPAGES);//
如為
TRUE
則不能實現打印功能,
//
而是建立打印機,祥查
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);
???????????????????? //
通知打印機驅動程序接受打印文檔
???????????????????? 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;//
轉化到
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)
????????????????????????????????????????? {
??????
????????????????????????????????????????? //
選定頁碼范圍
???????????????????????????????????????????????? page_Min = dlg.m_pd.nFromPage;
???????????????????????????????????????????????? page_Max = dlg.m_pd.nToPage;
????????????????????????????????????????? }
????????????????????????????????????????? else if (dlg.PrintSelection() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
選定的選擇區域
???????????????????????????????????????????????? //
暫時不知道怎么處理的
????????????????????????????????????????? }
????????????????????????????????????????? for(int i = 0; i < m_nCopies; i++)
????????????????????????????????????????? {
???????????????????????????????????????????????? for(UINT j = page_Min; j < page_Max + 1; j++)
???????????????????????????????????????????????? {
??????????????????????????????????????????????????????? if (dcPrinter.StartPage() < 0)//
只起到判斷作用,不
//
加不會影響正常打印
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? AfxMessageBox(_T("Could not start page"));
?????????????????????????????????????????????????????????????? bPrintOK = FALSE;
?????????????????????????????????????????????????????????????? break;
??????????????????????????????????????????????????????? }????????????????????????????????
??????????????????????????????????????????????????????? OnPrint(dcPrinter, j, rato);
??????????????????????????????????????????????????????? if (dcPrinter.EndPage() <= 0)? //
告訴打印驅動換
//
頁,如果不加則將所有頁打在一張紙上
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? 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)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
選定頁碼范圍
???????????????????????????????????????????????? page_Min = dlg.m_pd.nFromPage;
???????????????????????????????????????????????? page_Max = dlg.m_pd.nToPage;
????????????????????????????????????????? }
????????????????????????????????????????? else if (dlg.PrintSelection() == TRUE)
????????????????????????????????????????? {
???????????????????????????????????????????????? //
選定的選擇區域
???????????????????????????????????????????????? //
暫時不知道怎么處理的
????????????????????????????????????????? }
????????????????????????????????????????? for(UINT j = page_Min; j < page_Max + 1; j++)
????????????????????????????????????????? {
???????????????????????????????????????????????? for(int i = 0; i < m_nCopies; i++)
???????????????????????????????????????????????? {
??????????????????????????????????????????????????????? if (dcPrinter.StartPage() < 0)//
只起到判斷作用,不
//
加不會影響正常打印
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? AfxMessageBox(_T("Could not start page"));
?????????????????????????????????????????????????????????????? bPrintOK = FALSE;
?????????????????????????????????????????????????????????????? break;
??????????????????????????????????????????????????????? }????????????????????????????????
????????????????????????????????????????????????
?????? OnPrint(dcPrinter, j, rato);
??????????????????????????????????????????????????????? if (dcPrinter.EndPage() <= 0)? //
告訴打印驅動換
//
頁,如果不加則將所有頁打在一張紙上
??????????????????????????????????????????????????????? {
?????????????????????????????????????????????????????????????? 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)
?????????????????????????????????? {
????????????????????????????????????????? //
選定頁碼范圍
????????????????????????????????????????? page_Min = dlg.m_pd.nFromPage;
????????????????????????????????????????? page_Max = dlg.m_pd.nToPage;
?????????????????????????????????? }
?????????????????????????????????? else if (dlg.PrintSelection() == TRUE)
?????????????????????????????????? {
????????????????????????????????????????? //
選定的選擇區域
????????????????????????????????????????? //
暫時不知道怎么處理的
?????????????????????????????????? }
?????????????????????????????????? for(UINT i = page_Min; i < page_Max + 1; i++)
?????????????????????????????????? {
????????????????????????????????????????? if (dcPrinter.StartPage() < 0)//
只起到判斷作用,不加不會
//
影響正常打印
????????????????????????????????????????? {
???????????????????????????????????????????????? AfxMessageBox(_T("Could not start page"));
???????????????????????????????????????????????? bPrintOK = FALSE;
dcPrinter.AbortDoc();
???????????????????????????????????????????????? break;
????????????????????????????????????????? }????????????????????????????????
????????????????????????????????????????? OnPrint(dcPrinter, i, rato);
????????????????????????????????????????? if (dcPrinter.EndPage() <= 0)//
告訴打印驅動換頁,如果不
//
加則將所有頁打在一張紙上
????????????????????????????????????????? {
???????????????????????????????????????????????? AfxMessageBox(_T("Could not end page"));
???????????????????????????????????????????????? bPrintOK = FALSE;
dcPrinter.AbortDoc();
???????????????????????????????????????????????? break;
????????????????????????????????????????? }
?????????????????????????????????? }
??????????????????????????? }
??????????????????????????? if (bPrintOK == TRUE)
??????????????????????????? {
?????????????????????????????????? dcPrinter.EndDoc();//
結束打印
?????????????
????????????? }
??????????????????????????? dcPrinter.Detach();//
釋放
DC
???????????????????? }???????????
????????????? }
?????? }????
}
?
//
具體的頁面繪制函數
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);
}
?
以上打印過程沒有考慮打印預覽功能,只是實現直接打印功能,現在的虛擬打印機軟件(
pdffactory
)已經很多了,個人感覺沒必要打印預覽功能。如果要要想實現打印預覽功能,那么我們就要考慮借用
MFC
的文檔-視圖結構或者對話框結構,原理是一樣的。介紹此類的文檔網絡上也很多,我剛開始是看
http://www.vckbase.com/document/viewdoc/?id=1618
才打算寫上面這么一篇的。后來發現
http://www.vckbase.com/document/viewdoc/?id=1270
,個人覺得很值得一讀的。
?
以下針對微軟封裝的幾個相應函數按調用順序做一簡單描述:
1.OnPreparePrinting
OnPreparePrinting
函數最先被調用,用來初始化打印機等。比如,若沒有安裝打印機,則該函數將提示用戶安裝打印機。用戶程序可以向其中加入別的初始化代碼,比如,計算打印你的文檔所需要的總頁數,然后調用視類中的打印機初始化函數BOOL ? DoPreparePrinting(CPrintInfopInfo)即可。而用AppWizard生成的代碼中,OnPreparePrinting函數將只是調用函數DoPreparePrinting,并傳遞參數。
2.OnBeingPrinting
OnBeingPrinting
函數是開始打印文檔前調用的函數,用戶可以在其中加入另一些對于打印過程的初始化代碼,比如分配打印過程中將要使用的“筆”(CPen)、“刷子”(CBrush)等,默認的代碼中該函數將直接返回。
3.OnPrepareDC
OnPrepareDC
函數用于在打印前準備打印設備場,如窗口大小、原點,視圖大小、原點等。同時該函數在視類顯示文檔內容時也被調用,默認的代碼中該函數調用基類中的OnPrepareDC函數。
4.OnPrint
OnPrint
函數則是具體的打印過程,它利用前面準備好的設備場進行打印。
5.OnEndPrinting
OnEndPrinting
函數是與OnBeginPrinting函數相對應的函數,它在打印完成后由應用框架調用,用于釋放在OnBeginPrinting中分配的“對象”,如“筆”、“刷子”等,其默認的代碼中該函數將直接返回。
?
這幾個函數中,OnPreparePrinting、OnBeginPrinting、OnEndPrinting函數在一次打印過程中將只被調用一次,不管這一次打印內容有多少頁,而OnPrepareDC、OnPrint函數則每打印一頁都將被調用一次,這種調用次序對于打印是很有用的。
?
好了,關于打印就總結到這里,最后還推薦一篇文章,對打印總括性比較好,如果覺得看我的代碼太累就看看http://www.vckbase.com/document/viewdoc/?id=1041
?