RTF 技术扩展 - 如何实现完美的分页打印
摘要: 本文给出了一种完美实现 RTF 文件分页打印的方法,并根据此方法实现了 RTF 文件的打印预览及打印。通过本方法实现的 RTF 文件的 WYSIWYG ( 所见即所得)显示、分页预览及分页打印三者在效果上完全一致,解决了以前预览与打印存在偏差的问题,无论在分页速度和效果上均取得了突破。同时,本方法还解决了分页效果与打印机相关的问题,做到了完全的设备无关。效果图如下:
关键字: RTF 、 Rich Text Format 、分页、打印。
一、背景介绍
RTF 文件的分页算法一致是困扰已久的话题,以前我的方法是采用逐行计算行高然后再手工分页的方法,该方法有很多不足之处:
1 、 正在计算的行必须在屏幕可视范围内;
2 、 每行的左缩进位置必须为正数;
3 、 逐行计算采用模拟键盘操作进行,速度很慢;
4 、 手工计算存在一些误差;
5 、 分页效果与打印机相关,导致不同打印机结果不一致。
综上几点原因,旧的分页算法存在稳定性差和计算不精确等问题,因此分页结果常常出现偏差。寻找一种稳定可靠、高效率的分页算法迫在眉睫。
二、新的分页算法简介
新的分页算法其核心采用以前我翻译的《 RichTextBox SDK 参考手册》一文中介绍的方法:主要方法是通过向 Rich Edit 控件发送 EM_FORMATRANGE 消息来将其输出重定向到指定设备,比如打印机。当然,也可以指定一个用于 Rich Text 文本格式化的输出设备,比如图片框。同时,可以使用 EM_SETTARGETDEVICE 消息来指定一个用于 Rich Text 文本格式化的目标设备。该消息用于实现 WYSIWYG (所见即所得)模式,即在该模式下应用程序采用默认打印机字体规格而非屏幕字体规格来定位文本。这样就实现了 RTF 文本的 WYSIWYG (所见即所得)显示、打印预览与最终打印。
需要说明的是,如果要保持 3 种方法在结果上的一致性,那么采用的 目标设备必须统一,这样才能保证渲染结果的统一。我们采用屏幕 Screen 对象来作为目标设备,这样就实现了渲染结果与打印机无关,避免了不同打印机其分页效果不同的问题。
下面对这几个消息进行详细讲解:
三、相关 Windows 消息和函数详解
EM_FORMATRANGE 消息
EM_FORMATRANGE 消息用于为指定设备格式化一定范围的文本,用于 Rich Edit 控件。
语法:
发送该消息,采用如下方法调用 SendMessage 函数:
lResult ~~~~ //~ 返回结果值 |
~~hWndControl, ~~~~ // 目标控件句柄
~~EM_FORMATRANGE, ~~~~ // 消息 ID
~~ ~~~~ //
~~ ~~~~ //
);
wParam
表示是否渲染文本。如果该参数为非 0 值,文本将被渲染;否则,文本仅仅被测量(不做实际渲染)。
lParam
指向一个 FORMATRANGE 结构体,该结构体包含输出设备相关信息,或者为 NULL 用于释放目标控件所绑定的信息。
返回值:
该消息返回适合该区域的最后一个字符位置,加 1 。
注释:
该消息通常与 EM_DISPLAYBAND 消息搭配,用于为输出设备诸如打印机等格式化 Rich Edit 控件中的内容。
非常重要的是,在你最后一次使用该消息后需要为 lParam 参数指定 NULL 值来释放所绑定的信息。另外,一旦你在某个设备使用该消息后,如果需要在不同设备再使用该消息,同样你必须先释放所绑定的信息。
消息信息:
头文件 | Richedit.h |
操作系统 | WindowsWindows NT |
参见:
Rich Edit Controls , EM_DISPLAYBAND , FORMATRANGE
FORMATRANGE 结构体
FORMATRANGE 结构体包含用于 Rich Edit 控件格式化其输出到指定设备的相关信息。该结构体用于 EM_FORMATRANGE 消息。
语法:
typedef struct _formatrange~{ |
HDC
HDC
RECT
RECT
CHARRANGE
} FORMATRANGE;
hdc | 渲染设备句柄。 |
hdcTarget | 目标设备句柄。 |
rc | 渲染区域,单位:缇。 |
rcPage | 渲染设备的整体区域,单位:缇。 |
chrg | CHARRANGE 结构体,表示用于格式化的文本范围。 |
结构体信息:
头文件 | Richedit.h |
操作系统 | WindowsWindows NT |
参见:
Rich Edit Controls , EM_FORMATRANGE
EM_DISPLAYBAND 消息
EM_DISPLAYBAND 消息用于显示 Rich Edit 控件的一部分内容,该文本采用前面 EM_FORMATRANGE 消息所指定的设备来格式化。
语法:
发送该消息,采用如下方法调用 SendMessage 函数
lResult~~~~ //~ 返回结果值 |
~~hWndControl, ~~~~ // 目标控件句柄
~~EM_DISPLAYBAND, // 消息 ID
~~~~~~ //
~~~~~ //
);
wParam
该参数不使用;必须等于 0 。
lParam
指向一个 RECT 结构体所表示的设备显示区域。
返回值:
如果操作成功,则返回 True ;否则返回 False 。
注释:
文本及组件对象模型( COM )对象将被该矩形所裁剪。程序不需要设置裁剪区域。
消息信息:
头文件 | Richedit.h |
操作系统 | WindowsWindows NT |
参见:
Rich Edit Controls , EM_FORMATRANGE , RECT
GetDeviceCaps 函数
GetDeviceCaps 函数用于获取指定设备的设备描述信息。
int GetDeviceCaps(
HDC hdc , // DC 句柄
int nIndex // 项目索引值
);
参数:
hdc
[in] DC 句柄。
nIndex
[in] 指定需要返回的项目。可以取下面的值:
索引 | 涵义 | |
DRIVERVERSION | 设备驱动程序版本。 | |
TECHNOLOGY | 设备工艺。取值可以为: | |
~ | DT_PLOTTER | 矢量绘图仪 |
~ | DT_RASDISPLAY | 光栅显示器 |
~ | DT_RASPRINTER | 光栅打印机 |
~ | DT_RASCAMERA | 光栅照相机 |
~ | DT_CHARSTREAM | 字符流 |
~ | DT_METAFILE | 图元文件 |
~ | DT_DISPFILE | 显示文件 |
~ | 如果 hdc 参数指向一个增强图元文件的 DC 句柄,设备工艺将参照 CreateEnhMetaFile 函数所指定的设备。确定是否是增强图元文件的 DC ,可以使用 GetObjectType |