映射模式是MFC甚至SDK界面编程第1个难点。打印则是第2个难点。这2个都是历史遗留的设计缺陷。这些缺陷还不至于到bug程度,但却很难用,不易理解。

MFC提供2个类来实现打印(预览),具体有CPrintDialog和CPageSetupDialog类。这2个类实际上提供3通用对话框。具体看下面3组代码。

“打印”对话框:
//main.h里面的代码
class CMyApp:public CWinApp
{
public:
  virtual BOOL InitInstance();
};

class CMainWindow:public CFrameWnd
{
public:
  CMainWindow();
protected:
  afx_msg void OnLButtonUp(UINT nFlage,CPoint point);
  DECLARE_MESSAGE_MAP();
};

//main.cpp里面的代码
#include <afxwin.h>
#include <afxdlgs.h>
#include "main.h"

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
  Enable3dControls();
  m_pMainWnd=new CMainWindow;
  m_pMainWnd->ShowWindow(m_nCmdShow);
  m_pMainWnd->UpdateWindow();
  return TRUE;
}
BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
  ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

CMainWindow::CMainWindow()
{
  Create(NULL,_T("MFC打印"),WS_OVERLAPPEDWINDOW,CRect(200,200,400,400));
}

void CMainWindow::OnLButtonUp(UINT nFlage,CPoint point)
{
  CPrintDialog dlg(FALSE);
  dlg.DoModal();
}

运行结果如下图:

在上图空白的客户区点击一次,出现如下图:

然后是第2个“打印设置”对话框,代码如下:

//main.h里面的代码
class CMyApp:public CWinApp
{
public:
  virtual BOOL InitInstance();
};

class CMainWindow:public CFrameWnd
{
public:
  CMainWindow();
protected:
  afx_msg void OnLButtonUp(UINT nFlage,CPoint point);
  DECLARE_MESSAGE_MAP();
};

//main.cpp里面的代码
#include <afxwin.h>
#include <afxdlgs.h>
#include "main.h"

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
  Enable3dControls();
  m_pMainWnd=new CMainWindow;
  m_pMainWnd->ShowWindow(m_nCmdShow);
  m_pMainWnd->UpdateWindow();
  return TRUE;
}

BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
  ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

));
}

void CMainWindow::OnLButtonUp(UINT nFlage,CPoint point)
{
  CPrintDialog dlg(TRUE);
  dlg.DoModal();
}

运行结果如下图:

在上图空白的客户区点击一次,出现如下图:

然后是第3个“页面设置”对话框,代码如下:

//main.h里面的代码
class CMyApp:public CWinApp
{
public:
  virtual BOOL InitInstance();
};

class CMainWindow:public CFrameWnd
{
public:
  CMainWindow();
protected:
  afx_msg void OnLButtonUp(UINT nFlage,CPoint point);
  DECLARE_MESSAGE_MAP();
};

//main.cpp里面的代码
#include <afxwin.h>
#include <afxdlgs.h>
#include "main.h"

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
  Enable3dControls();
  m_pMainWnd=new CMainWindow;
  m_pMainWnd->ShowWindow(m_nCmdShow);
   m_pMainWnd->UpdateWindow();
  return TRUE;
}

BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
  ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

));
}

void CMainWindow::OnLButtonUp(UINT nFlage,CPoint point)
{
  CPageSetupDialog dlg;
  dlg.DoModal();
}

运行结果如下图:

在上图空白的客户区点击一次,出现如下图:

以上3组代码都有2个共同特点:

①在main.cpp文件里面的第2行代码是#include <afxdlgs.h>。如果没有包含afxdlgs.h头文件,那么任何通用对话框类将都不能使用。

②3个对话框窗口都是锁定式对话框。

主窗口高度有意做高度改变,用于区别。为什么要有3个对话框,这就是最前面所说的“历史问题”。可以先看看Microsoft Office 2003的“打印”和“页面设置”对话框的界面。截图如下:

从以上2图可以看出Office自己的打印功能明显比系统MFC自带的3个对话框加起来的还要复杂,也更为合理。事实上,几乎各个大型软件会自己提供适合自己的打印界面,而不是使用系统自带的打印界面。如果非要使用系统自带的打印界面,那么建议使用第个对话框来设置页面,并从对话框的右下角的“打印机”按钮来设置打印机,这样差不多可以应付大部分打印需要。如果系统把3个界面合并成一个更通用的界面,那么打印功能会大大加强和易用。

以上代码均没有输出代码,以下代码给出MFC下的最原始、最核心、最根本的输出代码范例。

//main.h里面的代码
class CMyApp:public CWinApp
{
public:
  virtual BOOL InitInstance();
};

class CMainWindow:public CFrameWnd
{
public:
  CMainWindow();
protected:
  afx_msg void OnLButtonUp(UINT nFlage,CPoint point);
  DECLARE_MESSAGE_MAP();
};

//main.cpp里面的代码
#include <afxwin.h>
#include <afxdlgs.h>
#include "main.h"

CMyApp myApp;

BOOL CMyApp::InitInstance()
{
  Enable3dControls();
  m_pMainWnd=new CMainWindow;
  m_pMainWnd->ShowWindow(m_nCmdShow);
  m_pMainWnd->UpdateWindow();
  return TRUE;
}

BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
  ON_WM_LBUTTONUP()
END_MESSAGE_MAP()

,));
}

void CMainWindow::OnLButtonUp(UINT nFlage,CPoint point)
{
  CDC dc;
  CPrintDialog dlg(FALSE);
  if(dlg.DoModal() == IDOK)
  dc.Attach(dlg.GetPrinterDC());

  DOCINFO di;
  ::ZeroMemory(&di,sizeof(DOCINFO));
  di.cbSize = sizeof(DOCINFO);
  dc.StartDoc(&di);
  dc.StartPage();
  //各种CDC输出函数
  dc.EndPage();
  dc.EndDoc();
}

以上代码中的ZeroMemory函数是SDK函数,但是却不需要使用include命令来包含SDK下的任何h头文件。这是Visual C++已经默认自带并识别大量常用SDK函数了。这是一个不错的功能。

我自己并没有实体打印机做测试,所以只能用1行//各种CDC输出函数省略具体的输出函数。实际上,在StartPage()函数和EndPage()函数期间,并不会真正在打印机有任何输出,必须等到调用EndPage()函数才会把一页内容输出到打印机上,即使使用虚拟打印机或者“打印到文件”功能也是如此。

除以上功能外,MFC还在CView类里面提供9个函数来简化并规范化打印(预览)功能。其中5个函数可以参考《MFC Windows程序设计》的第2版(修订版)里面的第685页的表13-2的解释。剩余4个函数含义大致如下:

函数 说明
CView::OnFilePrint 打印
CView::OnFilePrintPreview 打印预览
CView::OnDraw 纯虚拟函数。用于具体绘图
CView::OnEndPrintPreview 结束打印预览

OnFilePrint函数已经被MFC映射到ID_FILE_PRINT的命令ID了。该函数不是虚拟函数,可以直接运行。

CView::OnFilePrintPreview函数已经被MFC映射到ID_FILE_PRINT_PREVIEW的命令ID了。该函数不是虚拟函数,可以直接运行。

ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView::OnFilePrintPreview)

《MFC Windows程序设计》的第2版(修订版)里面的第692页已经提供一个含有CView打印的例子,这里便不再给出。

《MFC Windows程序设计》的第2版(修订版)里面的第684页有“打印假脱机”。这里的“脱机”其实是指“后台打印技术”。

MFC打印的更多相关文章

  1. MFC对话框使用CPrintDialog实现打印,指定打印机、后台打印

    推荐下 不错. 对话框打印,网上一搜一大堆,基本分2类: A类: CPrintDialog.DoModal,然后在模态对话框里选打印机.打印配置: B类:GetPrinterDeviceDefault ...

  2. MFC覆盖OnPrepareDC实现“所见即所得”打印

    附件下载:http://files.cnblogs.com/mengdejun/print.zip void CPrintView::OnPrepareDC(CDC* pDC, CPrintInfo* ...

  3. 如何以编程方式打印到在 MFC 中的非默认打印机

    http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105790245b09c0252bd7a74a2485d315d2390f0750 ...

  4. Visual Studio C++ MFC界面常用参数更改(改变图标,添加控件,调试打印函数等等)

    背景 需要使用Visual Studio C++做一些界面.此篇文章既是记录Visual Studio C++在调整界面时常常遇见的问题. 正文 一.如何更改窗体图标,以及生成的.exe图标 更改窗体 ...

  5. MFC 实现打印机打印功能

    Visual C++6.0是开发Windows应用程序的强大工具,但是要通过它实现程序的打印功能,一直是初学者的一个难点,经常有朋友询问如何在VC中实现打印功能,他们往往感到在MFC提供的框架内实现这 ...

  6. MFC程序使用控制台打印

    1.在OnCreate窗口创建方法中调用控制台窗口创建方法,创建的窗口是与MFC主窗口共存亡的 参考地址:https://blog.csdn.net/Yong_Qi2015/article/detai ...

  7. MFC下调试日志的打印

    最近项目出现点小Bug,需要调试跟踪代码,于是乎写了份打印日志的代码. CLogFile.h文件 #if !defined(AFX_LOGFILE_H__288388CA_9A3E_4F3D_A2B8 ...

  8. MFC程序加打印(使用控制台)

    对于MFC界面编程,在调试过程常常希望时刻知道程序的运行状态,可以使用弹窗程序来进行显示,但这种操作非常的麻烦,因此可以考虑使用控制台程序,在控制台程序中添加输出信息.方法如下: 在stdafx.cp ...

  9. VS IDE环境下,windows GUI(Qt MFC,win32)使用控制台实时打印调试信息

    在工程属性的页面下,点击Build Events,在Build Events下点击Post-Build Event. 然后再Command Line里面输入以下命令: editbin /SUBSYST ...

随机推荐

  1. 【实战分享】又拍云 OpenResty / Nginx 服务优化实践

    2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...

  2. java代码之美(10)---Java8 Map中的computeIfAbsent方法

    Map中的computeIfAbsent方法 Map接口的实现类如HashMap,ConcurrentHashMap,HashTable等继承了此方法,通过此方法可以在特定需求下,让你的代码更加简洁. ...

  3. NodeJs安装步骤与淘宝镜像

    dir 列目录 lscd 路径 切换路径 cdmd 文件夹名 创建一个空文件夹 mdC: 切换盘符 cls 清屏 clear ping ip/网址 网络测试ipconfig -all 查看网络连接信息 ...

  4. CentOS7 systemctl tomcat常用配置

    开始配置tomcat 1.环境准备,安装java 在生产环境上,我一般使用oracle java,不使用openjdk,所以先卸载系统自带的openjdk yum remove java 下载orac ...

  5. 基于三层架构的增删改查Get知识点

    给DataGridView控件绑定datatable数据源之后总是会多一行,在属性里修改属性allowuserToaddrow值为false即可 不可编辑状态是设置成只读状态即可,英文属性readon ...

  6. Kafka控制器选举流程剖析

    1.概述 平时在使用Kafka的时候,可能关注的更多的是Kafka系统层面的.今天来给大家剖析一下Kafka的控制器,了解一下Kafka控制器的选举流程. 2.内容 Kafka控制器,其实就是一个Ka ...

  7. Linux基础知识第三讲,拷贝文件跟移动文件命令

    目录 Linux基础知识第三讲,拷贝文件跟移动文件命令 一丶常用命令 1.tree命令常用选项 2.cp复制文件命令 3.mv 命令的使用 Linux基础知识第三讲,拷贝文件跟移动文件命令 一丶常用命 ...

  8. SpringCloud系列——Feign 服务调用

    前言 前面我们已经实现了服务的注册与发现(请戳:SpringCloud系列——Eureka 服务注册与发现),并且在注册中心注册了一个服务myspringboot,本文记录多个服务之间使用Feign调 ...

  9. webpack4.0各个击破(1)—— html部分

    webpack作为前端最火的构建工具,是前端自动化工具链最重要的部分,使用门槛较高.本系列是笔者自己的学习记录,比较基础,希望通过问题 + 解决方式的模式,以前端构建中遇到的具体需求为出发点,学习we ...

  10. 杭电ACM2016--数据的交换输出

    数据的交换输出 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...