WIN32汇编语言教程:第09章 通用控件 · 9.4 使用Richedit控件(6)
2. 创建Richedit控件
创建Richedit控件的工作一般在主窗口的WM_CREATE消息中完成,创建的办法是使用CreateWindowEx函数:
.const szClassEdit db 'RichEdit20A',0 ... .code invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassEdit,NULL,\ WS_CHILD OR WS_VISIBLE OR WS_VSCROLL OR WS_HSCROLL \ OR ES_MULTILINE or ES_NOHIDESEL,\ 0,0,0,0,hWinMain,0,hInstance,NULL mov hWinEdit,eax
注意类名使用上的区别:1.0版使用“RichEdit”,2.0和3.0版本的类名有两种,ANSI版本使用的类名是“RichEdit20A”,Unicode版本使用的类名是“RichEdit20W”,例子中使用的是ANSI版本。
Richedit控件可以使用的风格有3组:标准的窗口风格、Edit控件风格和Richedit控件特有的风格。
在Edit控件可以使用的风格中,可供Richedit控件使用的有:
● ES_MULTILINE——可以编辑多行文字。
● ES_AUTOHSCROLL和ES_AUTOVSCROLL——自动滚动。
● ES_NOHIDESEL——失去键盘输入焦点的时候仍然显示选择区域。
● ES_READONLY——只读属性。
● ES_CENTER,ES_RIGHT和ES_LEFT——文本的对齐方式。
● ES_WANTRETURN——允许用户按回车键插入新的行。
但下列Edit控件风格不能在Richedit控件中使用:
● ES_LOWERCASE或ES_UPPERCASE——将控件中的文字全部转换成小写或大写。
● ES_PASSWORD——将控件中的文字显示为密码方式(显示为星号)。
下面列出的是部分Richedit控件特有的风格:
● ES_DISABLENOSCROLL——指定这个风格后,控件在不需要滚动条的时候(文字没有超出客户区大小)显示灰化状态的滚动条,而默认情况下,当不需要滚动条的时候,控件根本不会显示它。
● ES_NOIME——禁止输入法(IME)操作,仅用于亚洲语言版本。
● ES_SAVESEL——在失去键盘输入焦点的时候保存当前选择区域,默认状态下当控件在重新获得焦点的时候会将全部文本选中。
创建控件以后,需要发送EM_EXLIMITTEXT消息设置控件中能够容纳字符的总数,虽然Richedit控件中的文字长度可以支持到最大的文件尺寸,但默认情况下,控件还是将最大字符数限制为64 KB,所以如果读者发现Richedit控件也只能编辑64 KB字符的话,那并不是控件的错,而是没有告诉它具体的要求,EM_EXLIMITTEXT消息的使用方法是:
invoke SendMessage,hWinEdit,EM_EXLIMITTEXT,0,dwTextMax
其中dwTextMax指定了最大字符数。
9.4.2 Richedit控件的控制消息
1. 选择区域
选择区域就是用户在控件中通过拖动鼠标来选定的多个文字,选择了一段文字以后,用户以后的操作就是针对这段文字的,如按下Delete键可以删除整段文字,按Ctrl+C键将这段文字拷贝到剪贴板中,按Ctrl+V键用剪贴板中的内容替换这段文字等。
在程序中,选择区域可以被程序获取,也可以由程序自由设置,从编程角度来看,选择区域的用处有两个:
● 选定操作文本——与用户手工选定一段文本以便进行各种操作类似,程序在对文本进行操作之前也需要预先设置选择区域。
● 定位光标——控件中并没有专门的用来定位光标的控制消息,定位光标也是靠设置选择区域完成的。如果把选择区域的起始位置和结束位置设置为相同的,那么就相当于把光标定位到这个位置而不选定任何文字。
在Edit控件中,获取选择区域可以通过向控件发送EM_GETSEL消息:
invoke SendMessage,hRichedit,EM_GETSEL,lpdwStart,lpdwEnd
lpdwStart和lpdwEnd指向两个用来返回选定区域起始位置和结束位置的双字变量,也可以将这两个参数全部设置为NULL,因为消息的返回值也是位置数据,返回值的低16位是选定区域的起始位置,高16位是结束位置。
但是EM_GETSEL消息仅适用于控件中文本长度不超过64 KB的情况,如果Richedit中选择区域的起始位置或结束位置有一个落在了64 KB以外,那么消息仅返回−1,而不是正确的数值,所以最好还是使用EM_EXGETSEL消息,EM_EXGETSEL消息是Richedit的特有消息,不能在Edit控件中使用:
invoke SendMessage,hRichedit,EM_EXGETSEL,0,lpchr
lpchr参数指向一个CHARRANGE结构,用来接收选择区域的起始和结束位置,该结构定义如下:
CHARRANGE STRUCT cpMin DWORD ? ;选择区域的起始位置 cpMax DWORD ? ;选择区域的结束位置 CHARRANGE ENDS
如果cpMinx字段等于cpMax字段,表示选择区域的长度为0,而光标位于这个位置;如果cpMin等于0而cpMax等于−1,表示选定的是控件中的所有内容。
程序也可以通过发送对应的消息来设置选择区域:
invoke SendMessage,hRichedit,EM_SETSEL,dwStart,dwEnd invoke SendMessage,hRichedit,EM_EXSETSEL,0,lpchr
EM_SETSEL的参数中直接用dwStart和dwEnd指定选择区域的开始和结束位置,但是这个消息同样有64 KB长度的限制;EM_EXSETSEL消息没有这个限制,lpchr参数同样指向一个CHARRANGE结构,结构中包含了需要设定的位置。如果仅是移动光标而不选择任何区域,可以将起始位置和结束位置设置为相同的数值。
在程序中设置了选择区域(或改变了光标位置)后,可能这个区域和原来的选择区域位置相差太多,以至于落在了客户区的外面,用户已经看不到它了,如果希望控件能够卷动文字以便将新的位置落在客户区中,可以发送EM_SCROLLCARET消息,这个消息没有任何参数:
invoke SendMessage,hRichedit,EM_SCROLLCARET,0,0
在例子程序中,根据是否存在选择区域来决定是否允许拷贝和剪切功能。因为如果不存在选择区域,就没有文本可供拷贝或剪切,所以在_SetStatus子程序中使用下面的代码首先获取选择区域,并根据情况允许或禁止拷贝和剪切菜单项:
invoke SendMessage,hWinEdit,EM_EXGETSEL,0,addr @stRange mov eax,@stRange.cpMin .if eax == @stRange.cpMax ;不存在选择区域 invoke EnableMenuItem,hMenu,IDM_COPY,MF_GRAYED invoke EnableMenuItem,hMenu,IDM_CUT,MF_GRAYED .else ;存在选择区域 invoke EnableMenuItem,hMenu,IDM_COPY,MF_ENABLED invoke EnableMenuItem,hMenu,IDM_CUT,MF_ENABLED .endif
另外,在查找文本的_FindText子程序中,一开始也通过发送EM_EXGETSEL消息获取选择区域,这是为了获得光标位置以便设置查找的起始点,当找到文本以后,文本的位置在FINDTEXTEX结构的chrgText字段中返回,chrgText字段本身是一个CHARRANGE结构,所以直接在EM_EXSETSEL消息中使用它就可以将选择区域设置到找到的文字上:
invoke SendMessage,hWinEdit,EM_EXSETSEL,0,addr @stFindText.chrgText invoke SendMessage,hWinEdit,EM_SCROLLCARET,NULL,NULL
最后程序发送EM_SCROLLCARET消息卷动文字,以便找到的文本能够出现在用户的视野中。
2. 文本管理
文本管理涉及获取文本,设置文本以及一些辅助操作。
Richedit控件本身就是一个窗口,所以可以通过常规的函数对其中的文本进行操作,比如要获取和设置文本,可以调用GetWindowText或SetWindowText函数,也可以通过发送WM_GETTEXT和WM_SETTEXT消息来完成;如果需要获取控件中的文本长度,可以通过GetWindowTextLength函数或发送WM_GETTEXTLENGTH消息,不过所有这些操作针对的都是控件中的全部文字,无法实现细微的操作。
向控件发送控制消息仅针对选择区域操作则灵活得多,当通过EM_EXSETSEL消息设置好选择区域后,再通过EM_GETSELTEXT消息就可以获取当前选定的文本:
上页:第09章 通用控件 · 9.4 使用Richedit控件(5) 下页:第09章 通用控件 · 9.4 使用Richedit控件(7)