WIN32汇编语言教程:第09章 通用控件 · 9.3 使用工具栏(5)

invoke SendMessage,hToolbar,TB_ADDBUTTONS,uNumButtons,lpButtons

TB_ADDBUTTONS消息总是在工具栏的最后添加按钮,使用TB_INSERTBUTTON消息可以在几个按钮的中间插入新的按钮,但一次只能插入一个按钮,消息的wParam参数指定插入位置,lParam消息指向一个TBBUTTON结构:

invoke SendMessage,hToolbar,TB_INSERTBUTTON,iButtons,lpButton

当然,如果使用CreateToolbarEx函数创建工具栏,那么上面的步骤就全部由函数包办了,这就是使用专用函数的好处。

也可以通过发送TB_DELETEBUTTON消息来删除工具栏上的按钮,iButton参数指定按钮的位置索引,第一个按钮用0表示:

   invoke SendMessage,hToolbar,TB_DELETEBUTTON,iButton,0

除了这些消息,还有一些消息可以用来获取工具栏的当前状态,如表9.3所示。

表9.3 获取工具栏状态的消息

消息WParamIparam说明
TB_BUTTONCOUNT00返回工具栏上按钮的数量
TB_GETBITMAPidButton0返回指定按钮的图像索引
TB_GETBUTTONiButtonlpButton返回指定按钮的TBBUTTON结构
TB_GETROWS00返回多行工具栏当前包含的行数
TB_GETITEMRECTiButtonlpRect在lParam指定的位置返回包含指定按钮

的位置的RECT结构

所有消息的参数中,iButton指按钮的位置索引,idButton指按钮的命令ID值。

2. 移动和缩放工具栏

用默认参数建立的工具栏能够自动移动和缩放大小,当主窗口的宽度变宽的时候,即使不对工具栏进行调整,工具栏的宽度还是会自动扩展到父窗口的宽度。但有个小缺陷就是工具栏自动变宽的时候,图9.5中数字(1)所示的分隔线却不会自动变长,结果工具栏的外观似乎不是很好看,所以在主窗口的WM_SIZE消息中还是需要对工具栏进行调整。不过调整的方法很简单,只要对工具栏发送TB_AUTOSIZE消息就可以了:

invoke SendMessage,hToolbar,TB_AUTOSIZE,0,0

消息中不必指定位置和大小参数,工具栏会自动计算新的大小,消息发送以后分隔线也会被调整到正确的宽度,一切看起来就完美了。

3. 工具栏按钮的维护消息

工具栏按钮可以像菜单项一样有选中、允许和灰化等状态,在程序中可以使用一组TB_ISBUTTONxxxx类型的消息来检测按钮的状态:

 
invoke SendMessage,hToolbar,TB_ISBUTTONCHECKED,idButton,0 ;是否在选中状态
invoke SendMessage,hToolbar,TB_ISBUTTONENABLED,idButton,0 ;是否在允许状态
invoke SendMessage,hToolbar,TB_ISBUTTONHIDDEN,idButton,0 ;是否在隐藏状态
invoke SendMessage,hToolbar,TB_ISBUTTONINDETERMINATE,idButton,0 ;是否灰化
invoke SendMessage,hToolbar,TB_ISBUTTONPRESSED,idButton,0 ;是否在按下状态

对于上面这些消息,如果答案是肯定的,那么消息返回TRUE,否则消息返回FALSE。如果嫌每次调用只能检测一种状态显得比较麻烦,也可以发送TB_GETSTATE消息:

invoke SendMessage,hToolbar,TB_GETSTATE,idButton,0

函数会返回按钮所有状态的组合值(TBSTATE_INDETERMINATE,TBSTATE _CHECKED,TBSTATE_ENABLED,TBSTATE_HIDDEN或TBSTATE_PRESSED等状态的组合)。在上面这些消息中,idButton用来指定按钮对应的命令ID。

设置按钮的状态也可以通过一组消息来完成:

invoke SendMessage,hToolbar,TB_CHECKBUTTON,idButton,uState ;选中按钮
invoke SendMessage,hToolbar,TB_ENABLEBUTTON,idButton,uState   ;允许按钮
invoke SendMessage,hToolbar,TB_HIDEBUTTON,idButton,uState ;隐藏按钮
invoke SendMessage,hToolbar,TB_PRESSBUTTON,idButton,uState ;按下按钮

对于这些消息,如果uState指定为TRUE,那么按钮会分别被设置为选中、允许、隐藏和按下状态;如果uState指定为FALSE,按钮会被设置为非选中、灰化、显示和凸起的状态。

同样,要一次性设置所有状态,可以发送TB_SETSTATE消息:

   invoke SendMessage,hToolbar,TB_PRESSBUTTON,idButton,uState

uState参数可以指定为TBSTATE_INDETERMINATE,TBSTATE_CHECKED,TBSTATE _ENABLED,TBSTATE_HIDDEN或TBSTATE_PRESSED等按钮状态的组合值。

9.3.3 工具栏的通知消息

大部分通用控件向父窗口发送的通知消息是WM_NOTIFY,为了便于和菜单消息使用同一段命令处理的逻辑代码,当按动工具栏按钮的时候,工具栏控件向父窗口发送的是WM_COMMAND消息,但其他情况下发送的通知消息仍然是WM_NOTIFY消息。

工具栏发送的WM_NOTIFY消息主要用于显示工具提示和定制工具栏。

1. 工具提示

当工具栏的风格包含TBSTYLE_TOOLTIPS的时候,CreateToolbarEx函数自动创建一个工具提示控件(Tool Tip),并为工具栏上的每个按钮注册提示文本,当鼠标指针移动到按钮上并停留片刻的时候,工具提示信息会自动显示出来。

工具提示信息是工具提示控件通过包含TTN_NEEDTEXT通知码的WM_NOTIFY消息向父窗口索取的,所以这个WM_NOTIFY消息严格地说应该属于工具提示控件的通知消息而不是工具栏的通知消息,但这里的工具提示控件是CreateToolbarEx函数自动创建的,所以还是一起介绍。

在包含TTN_NEEDTEXT通知码的WM_NOTIFY消息中,lParam指向一个TOOLTIPTEXT结构——慢着!前面不是说WM_NOTIFY消息的lParam参数指向一个NMHDR吗?怎么又是TOOLTIPTEXT结构呢?由于不同控件的通知消息都使用WM_NOTIFY消息,有些通知消息可能需要附带其他数据,这时仅使用一个NMHDR结构来表达是不够的,Windows的处理办法是为需要附带其他数据的WM_NOTIFY消息定义不同的数据结构,但这些结构头部都是一个NMHDR结构,NMHDR结构以后才是其他字段,这样在得知通知码之前,把lParam参数指针当做一个NMHDR结构来处理总是正确的。而且只有先把lParam参数指针当做NMHDR结构处理并从中获取通知码以后,才真正知道lParam指向的究竟是什么结构。

好了,问题解决了,言归正传。TTN_NEEDTEXT通知码的lParam指向一个TOOLTIPTEXT结构,这个结构的定义是:

TOOLTIPTEXT STRUCT
 hdr           NMHDR     <>  ;头部位置是一个NMHDR结构
 lpszText     DWORD     ?   ;工具提示字符串指针
 szText       BYTE 80 dup (?) ;工具提示字符串缓冲区
 hInst         DWORD      ?       ;包含字符串资源的模块句柄
 uFlags        DWORD      ?       ;标志
TOOLTIPTEXT ENDS

当需要显示工具提示信息的时候,工具提示控件向父窗口发送TTN_NEEDTEXT通知码,父窗口将需要显示的提示字符串放在TOOLTIPTEXT结构中并返回以后,工具提示控件就会把它显示出来。设置TOOLTIPTEXT结构的办法有3种,读者可以任选其一:

(1)字符串包含在资源中,这时可以将hInst字段设置为包含资源的模块句柄,并把lpszText字段设置为字符串ID,其他字段保持为NULL,工具提示会自己使用LoadString函数装入字符串。

(2)将字符串放在内存中,将内存指针放入lpszText字段中,其他字段保持NULL。

(3)将字符串拷入szText字段中,其他字段保持NULL。

例子程序使用了第一种办法。由于NMHDR结构的idFrom字段已经返回了按钮的命令ID,所以在资源脚本文件中将字符串的ID和命令ID一一对应定义,然后使用第一种方法是最方便的,代码如下:

      .elseif eax == WM_NOTIFY
              mov    ebx,lParam
              .if    [ebx + NMHDR.code] == TTN_NEEDTEXT
                      assume ebx:ptr TOOLTIPTEXT
                      mov    eax,[ebx].hdr.idFrom
                      mov    [ebx].lpszText,eax
                      push      hInstance
                      pop    [ebx].hinst
                      assume ebx:nothing
                       ...

读者可以自己尝试一下其他的方法。

上页:第09章 通用控件 · 9.3 使用工具栏(4) 下页:第09章 通用控件 · 9.3 使用工具栏(6)

第09章 通用控件

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号