mfc对话框上添加打印预览和打印
以下的内容是照着CSDN上下载的一份代码写的,如有不对望指正
打印预览和打印流程
在对话框类建立一个框架类的对象指针成员,框架类可以派生自 CFrame,
当要打印的时候,现创建出框架对象,可以将当前的对话框的窗口对象传到框架对象中保存,为什么?下面会说到.
然后框架对象调用 Create 创建自己的窗口,
在框架的OnCreate函数中创建view, view是派生自 CScrollView 的,并且设置 m_nMapMode 为 MM_TEXT,这个最好在构造函数中
可以使用框架类的 CreateView
然后将打印的内容写入到 CBitmap 对象中,比如 m_bitmapPrint 中,如下代码可以将显示窗口的内容写入到 m_bitmapPrint
CRect rectWnd; CBitmap *pOldBitmap; CDC* pDC = GetDC(); CDC* pMemDC = new CDC; //获取窗口位图 GetWindowRect(rectWnd); m_bitmapPrint.DeleteObject(); m_bitmapPrint.CreateCompatibleBitmap(pDC, rectWnd.Width(), rectWnd.Height()); pMemDC->CreateCompatibleDC(pDC); pOldBitmap = pMemDC->SelectObject(&m_bitmapPrint); PrintWindow(pMemDC, 0); pMemDC->SelectObject(pOldBitmap); //释放内存 ReleaseDC(pMemDC); delete pMemDC;
然后调用框架类的 DoPrintView, 其中调用框架视图的 OnFilePrintPreview, 这2个函数名字是自己写的
在 DoPrintView 函数里需要将程序的主窗口设置成当前的 框架类 的窗口,用于欺骗MFC,让MFC知道当前的主窗口是 框架类窗口,这样才能打印.
当打印完成需要修改回去,切记!! 这就是为什么上面需要保存主窗口(对话框窗口)的原因.
CWinApp *pApp = AfxGetApp(); pApp->m_pMainWnd = this;
在框架视图的 OnFilePrintPreview 函数中需要创建一个 CPrintPreviewState 类对象,这个是个系统类,将关闭打印预览的回调函数设置进去,
然后调用 DoPrintPreview, DoPrintPreview 是开始打印预览的函数, 这个函数有个参数是 打印预览视图类 的 运行时,
CPrintPreviewState* pState = new CPrintPreviewState; pState->lpfnCloseProc = ProcClosePrintPreview; // 点叉关闭打印预览视图的回调函数 // 最好显示工具栏,可以在预览时直接点工具栏上的按钮打印,并且有放大缩小功能 // CPreviewPrint 派生自系统的 CPreviewView, 是打印预览的视图 // this 是框架视图 // 需要在程序的.rc文件中加入如下一行,不然不能建立工具栏 // #include "l.chs\\afxprint.rc" // 摘自 http://blog.csdn.net/autumn20080101/article/details/8815248 if(!DoPrintPreview(AFX_IDD_PREVIEW_TOOLBAR, this, RUNTIME_CLASS(CPreviewPrint), pState)) { TRACE0("Error: DoPrintPreview failed.\n"); AfxMessageBox(AFX_IDP_COMMAND_FAILURE); delete pState; }
这个打印预览视图需要派生自系统的 CPreviewView 类,然后就创建出打印预览视图的界面,注意这个视图不是之前框架里面那个视图
然后系统回调框架视图类的 OnPreparePrinting, 并传进来一个 CPrintInfo 类的指针参数,只需要在这里直接调用父类 CView 的 DoPreparePrinting,
然后系统回调框架视图类的 OnBeginPrinting, 并传进来一个 CDC 指针参数和 CPrintInfo 类的指针参数,这里可以设置打印多少页,
pInfo->SetMaxPage(3); // 可以设置多页,当设置多页时, pInfo 里的 m_nCurPage 成员会指示,从1开始计数
然后直接调用父类 CScrollView 的 OnBeginPrinting
这时就会调用打印预览视图的 OnDraw 函数, 直接调用父类 CPreviewView 的 OnDraw 函数,
如果在创建打印预览视图的时候指定了工具栏, 可以给工具栏post WM_IDLEUPDATECMDUI 消息 wParam == bDisableIfNoHandler
然后系统回调框架视图类的 OnPrint, 并传进来一个 CDC 指针参数和 CPrintInfo 类的指针参数,
然后发送消息给 对话框类, 将之前准备好的 m_bitmapPrint 给 StretchBlt 到 CDC 指针参数对应的 DC 中
CRect rectWnd; BITMAP bmGraphy; CBitmap bitmapTemp, *pOldBmpGraphy; CDC* pGraphyDC = new CDC; CDC* pDC = GetDC(); CDC* pPrintDC = (CDC*)wParam; // OnPrint 中的 CDC 指针参数 CPrintInfo* pInfo = (CPrintInfo*)lParam; // OnPrint 中的 CPrintInfo 指针参数 //pInfo 里的 m_nCurPage 成员会指示当前是哪一页,从1开始计数,根据这个修改内容就行 m_bitmapPrint.GetBitmap(&bmGraphy); pGraphyDC->CreateCompatibleDC(pDC); pOldBmpGraphy = pGraphyDC->SelectObject(&m_bitmapPrint); pPrintDC->StretchBlt(pInfo->m_rectDraw.left, pInfo->m_rectDraw.top, pInfo->m_rectDraw.Width(), pInfo->m_rectDraw.Height(), pGraphyDC, 0, 0, bmGraphy.bmWidth, bmGraphy.bmHeight, SRCCOPY); pGraphyDC->SelectObject(pOldBmpGraphy); //释放内存 ReleaseDC(pGraphyDC); delete pGraphyDC;
当你点击打印预览工具栏上的放大缩小的时候会调用 打印预览视图的 OnDraw 函数, 然后再次调用 框架视图的 OnPrint 函数,然后同上
到此打印预览完成
当你点击打印预览界面上的打印按钮时,系统回调 打印预览视图的 OnPreviewPrint 函数,可以直接发(WM_COMMAND, ID_FILE_PRINT)消息通知给 框架视图类
然后系统回调框架视图类的 OnPreparePrinting, 此时显示的是一个 CPrintDialog 对话框,然后点确定之后,
系统回调框架视图类的 OnBeginPrinting 和 OnPrint, 跟打印预览一样了
当关闭打印预览视图界面时可以点工具栏,也可以点右上角叉,
当点工具栏的关闭时,系统会回调 打印预览视图类的 OnPreviewClose 函数,因为此时程序的主窗口类是 框架类 而不是 主对话框类,(之前在 DoPrintView 设置的)
所以需要将程序的主窗口类设置成主对话框类,如果不设置会关闭整个程序而不是打印预览视图.还需要手动销毁 框架类,系统测试不会代替你销毁
如果是通过点击右上角非客户区的叉按钮,则会调用之前设置的关闭回调函数,可以在里面手动调用 打印预览视图 的 OnPreviewClose,但是,
不能手动销毁 框架类,系统会代替程序销毁的,所以在这里需要做判断
CPrintFrame* pFrame = (CPrintFrame*)::AfxGetMainWnd(); // 这里需要修改 CWinApp 对应的主窗口, 默认是框架类,需要设置成宿主的窗口类 // 如果不修改会将整个程序关掉 CWinApp* pApp = AfxGetApp(); pApp->m_pMainWnd = pFrame->m_pMainDlg; if(!m_bClickNCClose){ // 点击了工具栏上的关闭需要手动的销毁框架 // 点击了非客户区的关闭按钮就不需要手动销毁框架 pFrame->DestroyWindow(); }
以上在vs2005上调试通过,vs2010上关闭的时候都需要手动销毁