您的位置:首页 > 其它

Win32教程33-RichEdit控件.基础知识

2008-10-08 09:17 225 查看
http://211.90.241.130:22366/view.asp?file=109

有很多人要求我提供关于RichEdit控件的指南,经过这方面的大量编程实践,我想我终于可以开写关于RichEdit控件的指南了。诺,这个就是第一篇RichEdit指南。本指南将会描述涉及到RichEdit的几乎所有方面,起码是我所知道的关于它的所有方面。因为指南的信息量相当相当的大,所以我将它分成了几个部分,本篇是第一部分。在这篇指南里,你将会了解到什么是RichEdit控件,怎样创建它,怎样往里面载入数据和保存里面的数据。

理论
A richedit control can be thought of as a souped-up edit control. 它提供了普通简单Edit控件所缺少的很多令人合意的功能,譬如可以使用多种字体和字体大小,多级Undo/Redo,文本搜索,内嵌OLE对象,编辑的拖放支持等等。由于RichEdit控件有这么多功能,因此它独存于一个单独的DLL文件。这个意味着如果你要使用RichEdit控件,就不能象使用其他普通控件那样只调用InitCommonControls 函数。你必须先使用 LoadLibrary 来载入RichEdit DLL文件。

这里有个问题,就是至今为止RichEdit控件共有3个版本,版本1,2和3。下面的表格显示了每个版本的相应的DLL文件名。

DLL NameRichEdit versionRichedit Class Name
Riched32.dll1.0RICHEDIT
RichEd20.dll2.0RICHEDIT20A
RichEd20.dll3.0RICHEDIT20A
你会注意到版本2和3都使用了相同的DLL文件名,而且它们也使用了相同的类名!这样在你想要明确的使用RichEdit 3.0的功能的时候就会产生问题. 到目前为止,我还找到一个正式的方法来区分版本2.0和3.0.不过,有个解决方法工作良好,我会在后面演示给你看.

.data
RichEditDLL db "RichEd20.dll",0 ......data? hRichEditDLL dd ?.code invoke LoadLibrary,addr RichEditDLL mov hRichEditDLL,eax ...... invoke FreeLibrary,hRichEditDLL
当Richedit DLL文件被载入时,它会注册 RichEdit 窗口类,因此需要在你创建Richedit控件之前必须先要载入DLL.Richedit控件的类名是不同的。现在你可能会有一个问题要提:我怎么样才能够知道我要使用哪个版本的Richedit控件?如果你不需要使用那些特别的功能,使用最新的版本也不定是最适宜的.下面的表格列出了每个RichEdit版本提供的功能.

功能版本 1.0版本 2.0版本 3.0
选择条xxx
Unicode 编辑xx
字符段落格式xxx
文本搜索向前搜索向前/向后搜索向前/向后搜索
内嵌OLExxx
拖放编辑xxx
Undo/Redo单级多级多级
自动 URL 识别xx
加速键支持xx
非窗口操作xx
分行符CRLFCRCR (可以模拟1.0版本)
Zoomx
Paragraph numberingx
simple tablex
normal and heading stylesx
underline coloringx
hidden textx
font bindingx
上面的表格不是全面的:我只是列出了那些重要的功能.

创建RchEdit 控件

载入DLL文件后,你可以调用CreateWindowEx 来创建RichEdit控件,创建控件时你可以使用Edit控件风格和普通窗口风格,但是ES_LOWERCASE, ES_UPPERCASE 和 ES_OEMCONVERT 风格除外.

.const
RichEditID equ 300
.data
RichEditDLL db "RichEd20.dll",0 RichEditClass db "RichEdit20A",0
...
.data? hRichEditDLL dd ?
hwndRichEdit dd ?
.code
.....
invoke LoadLibrary,addr RichEditDLL
mov hRichEditDLL,eax invoke CreateWindowEx,0,addr RichEditClass,WS_VISIBLE or ES_MULTILINE or WS_CHILD or WS_VSCROLL or WS_HSCROLL, /
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hWnd,RichEditID,hInstance,0
mov hwndRichEdit,eax
设置缺省的文本和背景颜色
在使用Edit控件时设置文本和背景颜色可能有点问题,但是在RichEdit控件中已经修正了这个问题.要设置RichEdit的背景色,你要发送 EM_SETBKGNDCOLOR 消息给RichEdit控件.这个消息具有以下语法.

wParam == 颜色选项. 如果是0说明Windows使用 lParam 中的颜色值作为背景色.如果该参数不为0,Windows使用系统背景色.因为我们要发送该消息来改变背景色,所以我们必须令wParam为0.
lParam == 指定要设置的颜色的 COLORREF 结构,仅当 wParam 为 0 时才有效.

譬如, 如果我要设置背景为纯蓝色,我需要写入以下代码:

invoke SendMessage,hwndRichEdit,EM_SETBKGNDCOLOR,0,0FF0000h
要设置文本颜色,RichEdit控件提供了另外的新消息,EM_SETCHARFORMAT来做这个工作. 这个消息控制控件中一段选定的文本或者全部正文的格式. 这个消息的语法如下:

wParam == 格式选项:

SCF_ALL 本次操作影响控件中全部文本.
SCF_SELECTION 本次操作仅影响选定的文本
SCF_WORD or SCF_SELECTION 本次操作仅影响所选定的那个单词. 如果选定是空的话,仅将插入点(光标)设置到指定字的位置. SCF_WORD 标志必须跟 SCF_SELECTION 一起使用.

lParam == CHARFORMAT 或者 CHARFORMAT2 结构的指针,说明要使用的正文格式. CHARFORMAT2 只在 Richedit 2.0 和更高版本才提供.这个不是说在RichEdit 2.0以后你一定要使用 CHARFORMAT2 . 如果你不需要使用到 CHARFORMAT2 中新加的功能, 你仍然可以使用CHARFORMAT .

CHARFORMATA STRUCT
cbSize DWORD ?
dwMask DWORD ?
dwEffects DWORD ?
yHeight DWORD ?
yOffset DWORD ?
crTextColor COLORREF ?
bCharSet BYTE ?
bPitchAndFamily BYTE ?
szFaceName BYTE LF_FACESIZE dup(?)
_wPad2 WORD ?
CHARFORMATA ENDS

Field NameDescription
cbSize该结构的大小. RichEdit控件使用该域来判断该结构的版本是 CHARFORMAT 还是 CHARFORMAT2
dwMask位标记, 用来指定下面的那些成员是有效的.

CFM_BOLDdwEffects 成语中的 CFE_BOLD 值是有效的.
CFM_CHARSETbCharSet 成员是有效的。
CFM_COLORcrTextColor 成员跟 dwEffects中的 CFE_AUTOCOLOR 值是有效的.
CFM_FACEszFaceName 成员是有效的.
CFM_ITALICdwEffects 成员中的 CFE_ITALIC 值是有效的.
CFM_OFFSETyOffset 成员是有效的.
CFM_PROTECTEDdwEffects 成员中的 CFE_PROTECTED 值是有效的.
CFM_SIZEyHeight 成员是有效的.
CFM_STRIKEOUTdwEffects 成员中的 CFE_STRIKEOUT 值是有效的.
CFM_UNDERLINEdwEffects 成员中的 CFE_UNDERLINE 值是有效的.
dwEffects字符效果. 可以是以下值的组合

CFE_AUTOCOLOR使用系统正文颜色
CFE_BOLD粗体字符
CFE_ITALIC斜体字符
CFE_STRIKEOUT字符带删除线
CFE_UNDERLINE字符带下划线
CFE_PROTECTED字符是受保护的; 企图改变字体会产生一个EN_PROTECTED 通知消息.
yHeight字符高度, 单位是 twips ( 1/1440 英寸 或者 1/20 的打印机的打印点).
yOffset字符偏移,单位是 twips, 从基线算起.如果该成员是正值,字符是下标,如果负值,字符是下标.
crTextColor 正文颜色. 如果指定了 CFE_AUTOCOLOR 字符效果,这个值会被忽略.
bCharSet字符集
bPitchAndFamilyFont family and pitch.
szFaceName 字体名字,是一个空字符结尾的字符数组.
_wPad2填充
通过检查这个结构,你会发现我们可以改变正文效果(粗体,斜体,删除线,下划线),正文颜色 (crTextColor) 和字体外观/大小/字符集. 值得注意的是 CFE_RPOTECTED 标志. 具有该标志的正文会被标志上受保护标志,意味着当用户试图改变它时, EN_PROTECTED 这个通知消息会被发送到父窗口.同时你可以允许该更改是是否可以进行.

CHARFORMAT2 增加更多的正文风格,象字体权值,间距,正文背景色,字距调整等等.如果你不需要这些额外的功能,只要使用 CHARFORMAT即可.

要设置正文格式,你必须考虑你想要该格式应用到的正文的范围.RichEdit控件引入了字符正文范围的概念.RichEdit 分派给每个字符一个从0开始数字值:控件中的第一个字符具有数字ID值为0,第二个为1...等等。要说明一个正文范围,你必须提供给RichEdit控件两个数值:范围的第一个和最后一个字符的ID值。要跟 EM_SETCHARFORMAT 一起应用字符格式,你有最多3种选择:

1.应用于控件中的所有正文。 (SCF_ALL)
2.应用于当前选定的正文。 (SCF_SELECTION)
3.应用于当前选定的一个单词。 (SCF_WORD 或者 SCF_SELECTION)

第一、二种情况是直观的,最后一个选择需要一点解释。如果当前选择只覆盖了词中的一个或多个字符但是不是整个词,指定 SCF_WORD+SCF_SELECTION 标志将正文格式应用于整个单词。即使没有当前选定,只有插入点(光标)位于单词中,第三种情况下仍然会将正文格式应用到整个单词中。

要使用 EM_SETCHARFORMAT, 你需要填充 CHARFORMAT (或者 CHARFORMAT2) 结构的结果成员。譬如,如果我们要设置正文颜色,需要如下一样填充 CHARFORMAT 结构:

.data?
cf CHARFORMAT <>
....
.code
mov cf.cbSize,sizeof cf
mov cf.dwMask,CFM_COLOR
mov cf.crTextColor,0FF0000h
invoke SendMessage,hwndRichEdit,EM_SETCHARFORMAT,SCF_ALL,addr cf
以上的代码片段设置RichEdit控件的正文颜色为纯蓝色。注意当 EM_SETCHARFORMAT 发生时,如果控件中没有正文,在这个消息之后键入的正文将会使用消息 EM_SETCHARFORMAT 中指定的正文格式。

设置正文/保存正文

对于那些经常使用Edit控件的人来说,你们肯定对使用 WM_GETTEXT/WM_SETTEXT 来设置/保存 控制中的正文的方法很熟悉。这个方法对RichEdit仍然适用,但是如果文件很大的话这个方法不再是最有效的。Edit控件限制了正文长度,可以输入最多64K的正文。但是RichEdit控件可以接受比这个限制大的多的正文数据。要分配一个很大的内存块(譬如大约 10MB ) 来接受来自来自WM_GETTEXT 消息的正文是一件很麻烦的事. Richedit 控件为此提供了一个新的方法,就是 正文流(Text Streaming)。

要设置RichEdit文本,你只需给RichEdit简单的提供一个回调函数的地址,当一切准备好时,RichEdit 会调用回调函数,并将正文缓冲区的地址传递给它。回调函数会将要发送给RichEdit的数据填入缓冲区或者将缓冲区的数据读出,然后等待下一次调用自到操作完成。 范例程序是流入(设置正文)和流出(取出正文)两者的例子。你将会发现这个方法更加有效:这个缓冲区是RichEdit控件自己提供的,因此数据被分成了几个大块。这个操作包括两条消息: EM_STREAMIN 和 EM_STREAMOUT。

EM_STREAMIN 和 EM_STREAMOUT 两者使用同一个语法:

wParam == 格式选项.

SF_RTF 数据是RTF格式。
SF_TEXT 数据是简单正文格式。
SFF_PLAINRTF 只有那些对所有语系都共有的关键词才流入。
SFF_SELECTION 如果指定这个标志,流操作的目标就是当前选定的正文。如果你将正文流入,当前正文就会被替换,如果是流出,则只有那些当前选定的正文才流出。如果没有指定这个标志,操作就会影响到控件中的所有正文。
SF_UNICODE (RichEdit 2.0 或更高版本才提供)指定的是 Unicode 正文。

lParam == 指向一个 EDITSTREAM 结构,该结构定义如下:

EDITSTREAM STRUCT
dwCookie DWORD ?
dwError DWORD ?
pfnCallback DWORD ?
EDITSTREAM ENDS

dwCookie 应用程序定义的数值,将会被传递给由 pfnCallback 成员说明的回调函数。通常地我们传递一些重要的参数值给回调函数,譬如流入/流出 处理中使用到的文件句柄。
dwError 指示流入(读)或流出(写)操作的结果。0说明没有错误。非0值可以是 EditStreamCallback 函数的返回值或者说明控件遇到了错误。
pfnCallback 指向 EditStreamCallback 函数的指针,该函数是由用户定义,由RichEdit调用来传输数据的。RichEdit 将数据分开多个部分,重复地调用该函数,一次一部分地进行数据传输。

EditStream 回调函数具有以下定义:

EditStreamCallback proto dwCookie:DWORD,pBuffer:DWORD,
NumBytes:DWORD,
pBytesTransferred:DWORD

你必须在程序中按照以上原型来创建回调函数。然后将函数地址通过 EDITSTREAM 结构传递给EM_STREAMIN 或者 EM_STREAMOUT 。

对流入操作(设置RichEdit 控件中的正文):

dwCookie: 应用程序定义的数值,通过 EDITSTREAM 结构传递给 EM_STREAMIN 。
在这里我们几乎全部都是将用其内容来设置RichEdit正文的文件的句柄传给这个参数。
pBuffer: 指向RichEdit提供的缓冲区。用来接受回调函数中提供的正文数据。
NumBytes: 本次调用中你可以写入缓冲区(pBuffer)的最大正文字节数。你 必须 遵守这个限制,
也就是说你发送的数据的大小可以比NumBytes指定要小,但是不能大于这个值。
你可以将这个数值当作pBuffer缓冲区的大小。
pBytesTransferred: 指向一个双字(DWORD),你必须设置这个值来指示你实际上传输了多少字节数据到缓冲区。
这个值通常跟 NumBytes中的值是相等的. 唯一的例外是当要传送的数据少于缓冲区提供的大小时,
譬如到达文件尾时就是了。

对流出操作(读出RichEdit控件的正文):

dwCookie: 跟流入操作相同. 我们一般传递想要将数据写入的文件的句柄给这个参数。
pBuffer: 指向由RichEdit提供的缓冲区,里面的是RichEdit的正文。要得到其大小,你必须检查 NumBytes 的知.
NumBytes: pBuffer 指向的缓冲区的的数据的大小。
pBytesTransferred: 指向一个双字(DWORD),你必须设置这个值来指示你实际上从缓冲区里读出了多少字节数据。

回调函数返回0说明操作成功,而且如果还有数据需要读/写的话,RichEdit控件会继续调用它。如果操作中发生了错误,而且你想停止操作的话,你可以返回一个非0值,这样RichEdit就会丢弃pBuffer指向的数据。错误/成功返回值会在 EDITSTREAM 的 dwError 成员中返回,你可以 在SendMessage 返回后检查流操作的错误/成功状态。.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: