按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
图9。7 自定义工具栏对话框
当用户在指定位置插入一个按钮的时候,工具栏发送TBN_QUERYINSERT通知码询问父窗口是否允许此操作,这时lParam指向一个TBNOTIFY结构,这个结构定义如下:
TBNOTIFY STRUCT
hdr NMHDR ;显然,这里肯定是NMHDR结构
iItem DWORD ? ;按钮的位置索引
tbButton TBBUTTON ;包含按钮信息的TBBUTTON结构
cchText DWORD ? ;pszText中字符串的长度
pszText DWORD ? ;按钮的说明字符串
TBNOTIFY ENDS
如果程序允许在此按钮前面插入一个新按钮,那么返回TRUE,否则返回FALSE。另外当自定义对话框刚显示的时候,父窗口也会收到这个通知码,这时必须返回TRUE,否则对话框在屏幕上一闪就消失了。
当用户要删除一个按钮的时候,工具栏发送TBN_QUERYDELETE通知码,询问父窗口是否允许此操作,这时lParam也指向一个TBNOTIFY结构,用来说明将要删除的按钮,如果程序允许此操作则返回TRUE,否则返回FALSE。
。elseif ('ebx + NMHDRde' TBN_QUERYINSERT) ||
('ebx + NMHDRde' TBN_QUERYDELETE) ;现在ebx = lParam
mov eax;TRUE
ret
在例子程序中使用上面的代码来处理这两个通知码,也就是说对于全部的情况均返回TRUE,表示允许用户随意进行移动按钮和删除按钮的操作。
TBN_GETBUTTONINFO通知码的处理就比较复杂了,当工具栏需要全部按钮的信息的时候,会多次发送TBN_GETBUTTONINFO通知码,在例子程序中是这样处理的:
。elseif 'ebx + NMHDRde' TBN_GETBUTTONINFO ;现在ebx = lParam
assume ebx:ptr TBNOTIFY ;lParam也是指向一个TBNOTIFY结构
mov eax;'ebx'。iItem
。if eax 《 NUM_BUTTONS
mov ecx;sizeof TBBUTTON
mul ecx
add eax;offset stToolbar
invoke RtlMoveMemory;addr 'ebx'。tbButton;eax;sizeof TBBUTTON
invoke LoadString;hInstance;'ebx'。tbButton。idmand;
addr @szBuffer;sizeof @szBuffer
lea eax;@szBuffer
mov 'ebx'。pszText;eax
invoke lstrlen;addr @szBuffer
mov 'ebx'hText;eax
assume ebx:nothing
mov eax;TRUE
ret
。endif
首先来分析为什么要这样处理TBN_GETBUTTONINFO通知码。
工具栏控件每次总是发送一组TBN_GETBUTTONINFO通知码,并且每次TBNOTIFY结构中的iItem字段递增,父窗口需要每次在结构中返回一个按钮的信息,如果还有剩余的按钮信息没有告诉工具栏(比如在用按钮和可选按钮加起来总共有15个,现在返回了10个,那么还剩5个按钮信息没有告诉工具栏),则在消息的返回值中返回TRUE,工具栏由此知道还有多余的按钮,于是马上将iItem字段加1再次发送TBN_GETBUTTONINFO通知码,如此循环直到某一次消息的返回值是FALSE为止。
为什么工具栏不知道需要获取的按钮的数量,而需要由父窗口来确定呢?这是因为工具栏只维护栏上现存的按钮,当工具栏上当前有10个按钮的时候,如果在一组TBN_GETBUTTONINFO通知码中返回了15个按钮,这15个按钮中包括了已经在使用的10个按钮和可以添加上去的另外5个按钮,那么工具栏就会将这15个按钮和栏上现存的所有按钮比较,并把现存的10个按钮放在“自定义工具栏”对话框的右边,把剩余的5个放在对话框的左边。
在例子中可用的按钮总共是16个,如果在初始化的时候只需要显示前面10个按钮,那么在使用CreateToolbarEx函数的时候可以只指定10个按钮,在这种情况下,当定制工具栏时在一组TBN_GETBUTTONINFO通知码中返回全部16个按钮的时候,多余的6个按钮就会出现在对话框的左边。
另外,TBNOTIFY结构的pszText需要返回按钮的说明文字,否则对话框中左右两个列表框中只会显示按钮图像而没有说明文字。程序在这里使用和工具提示信息同样的文字,这些文字存放在资源中,所以例子代码从TBNOTIFY结构包含的TBBUTTON结构中取出idmand字段,使用LoadString函数从资源中读取以idmand为ID的字符串并将其放入pszText所指的缓冲区中,最后使用lstrlen函数求出字符串的长度并放入cchText字段中,这样对话框的列表框中就可以显示出按钮的名称字符串了。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。4 使用Richedit控件(1)
Richedit控件和Edit控件类似,可以用于文本的输入和编辑。但两者在功能上各有侧重点。
Edit控件广泛使用于对话框中,用来供用户输入少量的文字,因此加快速度和减少资源的占用是最重要的,各种高级编辑功能不是主要的,所以Edit控件在短小精悍的同时,也存在诸多限制,最主要的就是在单行模式下,能容纳的文本不能超过32 KB,在多行模式下也不能超过64 KB。
Richedit控件则侧重于文字的高级编辑功能,控件能够容纳的文本长度可以支持操作系统中的最大文件尺寸,并内置了很多高级编辑器才具有的特征,如多级的撤销或重做,向前或向后搜索,支持Unicode编辑等,最重要的就是支持RTF(Rich Text Format)格式的带段落格式的文本编辑。由于实现这些功能的代码比较复杂,所以Richedit控件的规模比较大,以至于Windows将它划分出来以一个单独的DLL库文件方式提供。
到目前为止,Richedit控件总共有3个版本,这些版本的功能有所不同,总的来说高版本包括了低版本的所有功能,但在某些细节的实现上又有些不同,随着版本的升高,一些设置工作也随之增多,所以如果不需要某些特殊功能的话,使用最高的版本可能并不是最适合的。
1。0版本的Richedit控件对应的库文件是Riched32。dll,Windows 95只提供1。0版本,文件名中的32是32位版本的意思(不过并没有一个Riched16。dll)。从Windows 98开始,系统中多了一个2。0版本的Richedit控件,Windows 2000开始则有了3。0版本。2。0版本和3。0 版本的库文件名都是Riched20。dll,同时Riched32。dll文件仍然存在于系统中,不过Riched20。dll文件名中的20总是让人迷惑,很多人第一次使用Richedit控件的时候误认为Riched32。dll的版本要比Riched20。dll的版本高。
除了在功能上的不同,不同版本Richedit控件的类名称也有所不同,表9。4列出了3个版本之间的一些区别。
表9。4 不同版本Richedit控件之间的区别
1。0版本
2。0版本
3。0版本
DLL库文件名
Riched32。dll
Riched20。dll
Riched20。dll
控件的类名
Richedit
Richedit20A
Richedit20W
Richedit20A
Richedit20W
拖放编辑
支持
支持
支持
流输入输出
支持
支持
支持
Unicode编辑
不支持
支持
支持
非窗口操作
不支持
支持
支持
自动URL识别
不支持
支持
支持
加速键
不支持
支持
支持
分行符
CR+LF
CR
CR(可模拟1。0版)
撤销/重做
支持单级
支持多级
支持多级
文本搜索
向前搜索
向前/向后搜索
向前/向后搜索
表9。4中列出的仅是一些最重要的区别,很多细微的区别并没有列出来,比如每个版本都可以为文本设定下划线,但3。0版比2。0版又增加了点、划、划-点、划-点-点等多种样式的下划线。
Richedit控件的2。0版本和3。0 版本使用的控件名和类名是相同的,有时候为了使用某些版本特有的功能,需要预先检测版本号,但Microsoft并没有提供一个官方的检测方法,所以必须利用一些版本之间的区别来进行检测(这种方法好像在检测不同的CPU),比如,排版样式功能(TYPOGRAPHY)是3。0版本才支持的,设置排版样式选项使用EM_SETTYPOGRAPHYOPTIONS消息,如果排版样式被设置后能够再检测到,说明控件的版本肯定是3。0的,代码如下:
invoke SendMessage;hwndRichEdit;EM_SETTYPOGRAPHYOPTIONS;
TO_SIMPLELINEBREAK;TO_SIMPLELINEBREAK
invoke SendMessage;hwndRichEdit;EM_GETTYPOGRAPHYOPTIONS;1;1
。if eax0 ;说明设置消息没被处理,版本是2。0版
mov dwVersion;2
。else
mov dwVersion;3
。endif
另外,也可以通过检测操作系统来确定Richedit控件的版本,如2。0版本在Windows 98和Windows NT 4。0中使用,而Windows 2000使用的是3。0版本。
在本节中,用一个简单的例子来演示Richedit控件的使用,包括如何创建控件、如何使用流操作装入和输出文件以及如何进行文本查找等,由于篇幅有限,程序并没有演示所有的高级编辑功能,程序代码存放在所附光盘的Chapter09Richedit目录中,其中汇编源代码Richedit。asm文件的内容如下:
。386
。model flat; stdcall
option casemap :none
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Include 文件定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
include windows。inc
include user32。inc
includelib user32。lib
include kernel32。inc
includelib kernel32。lib
include dlg32。inc
includelib dlg32。lib
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Equ 等值定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN equ 1000
IDA_MAIN equ 2000
IDM_MAIN equ 2000
IDM_OPEN equ 2101
IDM_SAVE equ 2102
IDM_EXIT equ 2103
IDM_UNDO equ 2201
IDM_REDO equ 2202
IDM_SELALL equ 2203
IDM_COPY equ 2204
IDM_CUT equ 2205
IDM_PASTE equ 2206
IDM_FIND equ 2207
IDM_FINDPREV equ 2208
IDM_FINDNEXT equ 2209
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 数据段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
。data?
hInstance dd ?
hWinMain dd ?
hMenu dd ?
hWinEdit dd ?
hFile dd ?
hFindDialog dd ?
idFindMessage dd ?
szFileName db MAX_PATH dup (?)
szFindText db 100 dup (?)
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。4 使用Richedit控件(2)
。data
stFind FINDREPLACE