映射模式是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. Java中需要知道的关键字

    Java中有一些或常用,或不常用,但却不得不知关键字,本篇文章将讨论这些关键字的作用. transient transient关键字可能用的不是那么频繁,但却是一个很重要的关键字,它的作用是在对象序列 ...

  2. 4.DOM

    定义 文档对象模型(Document Object Model)是一种用于HTML和XML文档的编程接口. 查找元素 1.直接查找 document.getElementById 根据ID获取一个标签 ...

  3. Python合并多个Excel数据

    安装模块 1.找到对应的模块  http://www.python-excel.org/ 2.用pip install 安装 pip install xlrdpip install XlsxWrite ...

  4. 华为oj之求int型正整数在内存中存储时1的个数

    题目: 求int型正整数在内存中存储时1的个数 热度指数:4427 时间限制:1秒 空间限制:32768K 题目描述 输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数. 输入描述: ...

  5. 什么是SOAP,有哪些应用

    SOAP 是一种轻量级协议,用于在分散型.分布式环境中交换结构化信息. SOAP 利用 XML 技术定义一种可扩展的消息处理框架,它提供了一种可通过多种底层协议进行交换的消息结构. 这种框架的设计思想 ...

  6. 无法使用 xxxx附加到应用程序

    以管理员运行cmd,输入netsh   winsock   reset ,重启电脑,OK. 出现这个错误的原因一般是因为游戏的缘由,本人亲测.

  7. Zookeeper~Linux环境下的部署

    介绍 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...

  8. Chapter 5 Blood Type——27

    And then Mike staggered through the door, now supporting a sallow-looking Lee Stephens, another boy ...

  9. Chapter 4 Invitations——26

    "I wanted to ask you something, but you sidetracked me," he chuckled. He seemed to have re ...

  10. 基于 Zookeeper 的分布式锁实现

    1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...