windows环境下32位汇编语言程序设计-第52章
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
数同样指向一个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消息就可以获取当前选定的文本:
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。4 使用Richedit控件(7)
invoke SendMessage;hWinEdit;EM_GETSELTEXT;0;lpBuffer
lpBuffer用来指定接收文本的缓冲区,由于没有参数指定缓冲区的大小,所以程序必须使用足够大的缓冲区,不过这不是问题,因为通过检查选择区域可以预先得知返回文本的大小,消息的返回值是返回到缓冲区中的字符串的长度(不包括末尾的0字符)。
通过发送EM_REPLACESEL消息可以替换选择区域中的文本,如果当前的选择区域长度不为0的话,选择区域的文本被消息指定的字符串所代替,如果选择区域长度为0,则指定的字符串被插入到当前光标位置:
invoke SendMessage;hWinEdit;EM_REPLACESEL;fCanUndo;lpString
其中fCanUndo参数指出本次替换操作是否可以撤销,如果指定TRUE,则控件保存撤销信息以便用户可以按Ctrl+Z键进行撤销,指定FALSE的话操作就不能被撤销。lpString参数指向插入或替换用的字符串,字符串以0结尾。
除了获取和设置文字,还有一系列的控制消息可以用来进行定位操作,比如想要选定一整行内容,就必须知道某一行的起始位置和结束位置;另外,有时候也需要在字符位置和行号之间进行转换计算,对于这些要求,把所有文本从控件中读出来再自己进行处理显然是很麻烦的,幸好Richedit控件已经提供了这些功能。
通过发送EM_EXLINEFROMCHAR消息可以得知指定的字符位于哪一行中:
invoke SendMessage;hWinEdit;EM_EXLINEFROMCHAR;0;dwCharPos
mov dwLine;eax
其中dwCharPos指出字符的位置(以0开始),消息将返回字符所处的行号。在所有这些消息中,字符位置和行号都是从0开始计算的,也就是说第1行的行号用0表示。
EM_LINEINDEX消息则完成逆运算,它返回指定行号的第一个字符的位置,dwLine参数为输入的行号,如果dwLine参数输入?1的话,代表的是当前行(光标所在的行):
invoke SendMessage;hWinEdit;EM_LINEINDEX;dwLine;0
mov dwCharPos;eax
该消息返回指定行的起始字符的位置,如果指定的行号超过了控件中文本的总行数,那么消息将返回?1。控件中包含文本的总行数可以通过EM_GETLINECOUNT消息获取:
invoke SendMessage;hWinEdit;EM_GETLINECOUNT;0;0
mov dwTotalLines;eax
如果想获取某一行的长度,有好几种方法,比如可以两次使用EM_LINEINDEX消息获取本行和下一行文字的起始位置,再相减就得出了行的长度;也可以用EM_LINELENGTH直接获取:
invoke SendMessage;hWinEdit;EM_LINELENGTH;ich;0
mov dwLineLength;eax
不过EM_LINELENGTH消息中的ich参数并不是行号,而是行中任意一个字符的位置,所以想以行号为参数获取行长度的话,还需要先用EM_LINEINDEX消息将行号转换到字符位置后再使用EM_LINELENGTH消息。这个消息还有个特殊用途,当ich参数指定为…1的时候,返回值是选定区域跨越的多个行中没有被选定的字符的总数,这有什么用处呢?显然,当按下了Delete键删除了选择区域时,剩下的行的长度就是这个返回值。
要想获取某一行的内容也有多种办法,比如可以先选定某个行,再用EM_GETSELTEXT消息来完成,但最简单的办法是使用EM_GETLINE消息:
mov word ptr szBuffer;sizeof szBuffer
invoke SendMessage;hWinEdit;EM_GETLINE;dwLine;addr szBuffer
其中dwLine参数指定要获取的行号,lpBuffer参数指向用来接收字符串的缓冲区,注意:缓冲区的第一个字(不是双字!)必须预先指定为缓存区的长度!另外,接收的字符串并不包括结束符0,所以在发送消息之前最好先把缓冲区全部清零,否则会和缓冲区中原有的数据混在一起。消息的返回值是返回到缓冲区中的字符串的长度。
3。 设置文本格式
Richedit控件支持两种模式:带格式文本RTF(Rich Text Format)模式和不带格式文本(Plain Text)模式。在默认状态下控件处于RTF模式,在这种模式下,程序可以对控件中的不同文字分别设置不同的格式,这些格式可以被保存到*。rtf文件中。而在Plain Text模式下,只能将控件中的全部文字设置统一的格式,而且这些格式仅表现在“显示”上,不会被保存到*。txt文件中。
在控件窗口被创建后可以通过发送EM_SETTEXTMODE消息来设置工作模式,这条消息仅对2。0版本以上的Richedit控件有效:
invoke SendMessage;hWinEdit;EM_SETTEXTMODE;dwTextMode;0
当dwTextMode参数指定为 TM_PLAINTEXT 的时候,控件切换到不带格式模式;指定为TM_RICHTEXT的时候,控件切换到RTF模式。这个消息也可以用来设置重做/撤销的模式,在dwTextMode参数中同时指定TM_SINGLELEVELUNDO标志可以将控件设置为单级重做/撤销模式;指定TM_MULTILEVELUNDO标志则设置为多级重做/撤销模式。
要设置文本格式可以通过发送EM_SETCHARFORMAT消息,这个消息设置控件中一段选定的文本或者全部正文的格式,消息的用法如下:
invoke SendMessage;hWinEdit;EM_SETCHARFORMAT;uFlags;lpFmt
uFlags参数表示指定的格式所应用的范围,它可以是下面的数值。
● SCF_ALL——为控件中的全部文本设置指定的格式。
● SCF_SELECTION——仅为选择区域设置指定的格式,如果选择区域为空,则以后在此位置插入的新字符使用此格式。
● SCF_WORD 与SCF_SELECTION——将格式应用到选定的单词上,如果选择区域没有落在整个单词上,那么格式会扩展到整个单词上,SCF_WORD标志必须和SCF_SELECTION标志一起使用。
lpFmt参数则指向一个CHARFORMAT或CHARFORMAT2结构,CHARFORMAT结构可以在所有版本中使用,而CHARFORMAT2结构仅可以在2。0及以上版本使用,CHARFORMAT2结构是CHARFORMAT结构的扩展,下面是CHARFORMAT2结构的定义:
CHARFORMAT2 STRUCT
CbSize DWORD ? ;结构长度
dwMask DWORD ? ;字段掩码
dwEffects DWORD ? ;文字效果
yHeight DWORD ? ;文字高度
yOffset DWORD ?
crTextColor DWORD ? ;文本颜色
bCharSet BYTE ?
bPitchAndFamily BYTE ?
szFaceName BYTE LF_FACESIZE dup(?) ;字体名称
;CHARFORMAT结构的定义到此为止
wWeight WORD ?
sSpacing WORD ?
crBackColor DWORD ?
lcid DWORD ?
dwReserved DWORD ?
sStyle WORD ?
wKerning WORD ?
bUnderlineType BYTE ?
bAnimation BYTE ?
bRevAuthor BYTE ?
bReserved1 BYTE ?
CHARFORMAT2 ENDS
CHARFORMAT2结构中szFaceName字段以前的内容就是CHARFORMAT结构,结构中各字段的含义如下。
● cbSize——结构的大小,控件使用该字段来判断结构的版本是CHARFORMAT还是 CHARFORMAT2,所以在将结构传递给控件前必须将这个字段设置为正确的数值。
● dwMask——字段掩码,用来指定结构中哪些字段是有效的,如果没有使用对应的标志,即使某些字段的内容被设置,控件也不会使用它,dwMask中可以使用的标志可以是下面数值的组合:
■ CFM_BOLD——dwEffects字段中CFE_BOLD 值是有效的。
■ CFM_CHARSET——bCharSet字段是有效的。
■ CFM_COLOR——crTextColor字段和dwEffects中的 CFE_AUTOCOLOR 值是有效的。
■ CFM_FACE——szFaceName字段的值是有效的。
■ CFM_ITALIC——dwEffects字段中的CFE_ITALIC值是有效的。
■ CFM_OFFSET——yOffset字段是有效的。
■ CFM_PROTECTED——dwEffects字段中的CFE_PROTECTED值是有效的。
■ CFM_SIZE——yHeight字段是有效的。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。4 使用Richedit控件(8)
■ CFM_STRIKEOUT——dwEffects字段中的CFE_STRIKEOUT值是有效的。
■ CFM_UNDERLINE——dwEffects字段中的CFE_UNDERLINE值是有效的。
● dwEffects——字符效果,可以是以下值的组合:
■ CFE_AUTOCOLOR——使用系统正文颜色。
■ CFE_BOLD,CFE_ITALIC,CFE_STRIKEOUT和CFE_UNDERLINE——粗体字符、斜体字符、带删除线和带下划线。
■ CFE_PROTECTED——字符是受保护的,企图改变字符的话控件会向父窗口发送一个EN_PROTECTED通知消息。
● yHeight——字符高度,单位是1/1 440 英寸(或1/20磅),如果这里是180,换算到“字体选择”通用对话框中的尺寸就是9磅(180×1/20=9)。
● yOffset——从基线算起的字符偏移,单位同上,如果该成员是正值,字符显示为上标;如果是负值,字符显示为下标。
● crTextColor——正文颜色,如果在dwEffects字段中指定了CFE_AUTOCOLOR标志,那么这个值会被忽略。
● bCharSet和bPitchAndFamily——字符集。
● szFaceName——用字符串表示的字体名字。
通过填充这个结构并将它通过EM_SETCHARFORMAT消息传送给控件,可以改变文字的效果(粗体、斜体、带删除线、带下划线等),正文颜色(crTextColor),字体外观(szFaceName)和字体大小(yHeight),以及使用的字符集等。使用CHARFORMAT2结构可以设置更多的文本风格,如字间距与正文背景色等。如果不需要这些额外的功能,那么只要使用CHARFORMAT结构就可以了。
例子程序Richedit。asm中只演示了使用Plain Text模式为所有文本设置字体的方法:
nst
szFont db '宋体';0
de
invoke SendMessage;hWinEdit;EM_SETTEXTMODE;TM_PLAINTEXT;0
invoke RtlZeroMemory;addr @stCf;sizeof @stCf
mov @stCf。cbSize;sizeof @stCf
mov @stCf。yHeight;9 * 20
mov @stCf。dwMask;CFM_FACE or CFM_SIZE or CFM_BOLD
invoke lstrcpy;addr @stCf。szFaceName;addr szFont
invoke SendMessage;hWinEdit;EM_SETCHARFORMAT;0;addr @stCf
程序首先将控件的模式设置为Plain Text模式,然后定义了一个名为@stCf的CHARFORMAT结构,将结构长度设置为CHARFORMAT结构的长度,然后在dwMask 字段中使用CFM_FACE, CFM_SIZE和CFM_BOLD标志,表示只使用字体、字体大小和字体粗细参数,最后发送EM_SETCHARFORMAT消息将控件中的全部文字设置为大小为9磅(小五号)的“宋体”。
4。 装入和保存文本
显然,使用GetWindowText和SetWindowText函数来保存和装入文本是可行的,但是RichEdit控件支持很大的文件,当文件足够大的时候,使用这种方法就很麻烦,因为必须首先要分配一块足够大的内存用做缓冲区,为了解决这个问题,Richedit控件提供了一种新方法,那就是文本流(Text Streaming)。
考虑这样一种情况:为了装入文本,可以申请一块大小合适的缓冲区(当