⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 009.txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:

    IDM_SAVE "保存文件"

    IDM_PAGESETUP "页面设置"

    IDM_PRINT "打印"

    IDM_COPY "拷贝"

    IDM_CUT "剪切"

    IDM_PASTE "粘贴"

    IDM_FIND "查找"

    IDM_REPLACE "替换"

    IDM_HELP "帮助"

END

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

资源脚本文件中定义了一些菜单,和状态栏例子程序一样,这些菜单也是仅用来做演示用途的,源程序中并没有书写处理菜单项的代码。

字符串表中定义的字符串是供工具提示信息使用的。

例子程序在主窗口的WM_CREATE消息中使用CreateToolbarEx函数建立工具栏。可以注意到,主程序建立了一个标准的窗口,而不是使用对话框做主窗口,这是为什么呢?这是因为在对话框中无法实现工具栏的高级功能,原因如下:

对话框过程的返回值是用来通知“对话框管理器”是否处理了相关消息的,这个返回值并不会被对话框管理器返回到工具栏子窗口去,对于大部分的控件来说,向父窗口发送WM_NOTIFY消息时并不需要父窗口回应一个返回值,但对于工具栏来说,父窗口必须根据WM_NOTIFY消息的处理情况返回TRUE或FALSE,工具栏要根据返回值再做不同的动作,如果返回值无法返回,就意味着工具栏无法做正确的动作。

所以在对话框中是无法使用工具栏的高级功能(如用户定制按钮等)的,但仅为了使用对话框的按钮当做菜单快捷按钮的情况不在此列,因为这时只需要处理WM_COMMAND消息,WM_COMMAND消息并不需要返回一个值。

例子程序中要演示用户定制工具栏按钮的功能,无法使用对话框当做主窗口,所以程序建立了一个常规的窗口。

9.3.1  创建工具栏

创建工具栏的专用函数是CreateToolbarEx,使用CreateWindowEx函数利用类名“ToolbarWindow32”也可以创建工具栏,但CreateWindowEx函数仅创建一个空的工具栏,在创建完成后还要初始化工具栏以及分多次插入按钮,而CreateToolbarEx函数可以一次创建工具栏以及上面的全部按钮。

CreateToolbarEx函数的用法是:

invoke  CreateToolbarEx,hwnd,ws,wID,nBitmaps,hBMInst,wBMID,lpButtons,\

  iNumButtons,dxButton,dyButton,dxBitmap,dyBitmap,uStructSize

mov hToolbar,eax

各参数的说明如下。

hwnd参数是父窗口的句柄,ws是工具栏的风格,wID是工具栏的子窗口ID,这几个参数也可以用在使用CreateWindowEx函数创建工具栏的调用中,ws参数使用的窗口风格必须包括WS_CHILD和WS_VISIBLE,另外还可以组合使用下面的特殊风格:

 

  


9.3 使用工具栏(4)

● TBSTYLE_FLAT——按钮的样式为平面样式,如果指定TBSTYLE_FLAT风格,创建的工具栏如图9.5上方的工具栏所示,如果不指定这个风格,则创建如图9.5下方所示的传统样式的工具栏。

● CCS_NODIVIDER——工具栏边上没有分隔线,如果指定这个风格,那么图9.5中就不会有数字(1)标出的横线。

● TBSTYLE_WRAPABLE——工具栏支持多行显示。

● CCS_TOP,CCS_BOTTOM或CCS_NOMOVEY——指定工具栏的位置,分别表示工具栏位于窗口的上方(默认风格)、底部和不会自动在垂直方向移动。

● CCS_NOPARENTALIGN——工具栏自动设置自己的高度,但不自动设置宽度和位置。

● CCS_NORESIZE——禁止工具栏的自动缩放功能,相当于禁止了上面的CCS_TOP、CCS_BOTTOM,CCS_NOMOVEY和CCS_NOPARENTALIGN风格。

● CCS_ADJUSTABLE——允许用户在按下Shift键的同时通过拖动工具栏上的按钮来调整按钮位置以及删除按钮。

● TBSTYLE_ALTDRAG——对CCS_ADJUSTABLE风格的工具栏将拖动时的按键由Shift键改为Alt键。

● TBSTYLE_TOOLTIPS——工具栏支持工具提示信息。



图9.5  工具栏的风格

hBMInst和wBMID参数用来指定绘画工具栏上的按钮使用的位图,位图可以在资源中定义也可以是已经装入内存的位图。如果使用资源中的位图,那么hBMInst指定包含位图资源的模块的实例句柄,wBMID指定位图资源的ID;如果hBMInst指定为NULL,那就表示要使用一个已经装入内存的位图,这时wBMID必须指定一个合法的位图句柄。

指定了使用的位图以后,nBitmaps,dxBitmap和dyBitmap参数继续给出了位图的属性,工具栏中的每个按钮并不使用一幅单独的位图,而是所有按钮的位图水平排列在一起组成一幅大的位图,nBitmaps参数说明了这幅大位图中包含多少个按钮位图,dxBitmap和dyBitmap参数指出了单个按钮位图的宽度和高度。显然,整个位图的高度就等于dyBitmap,宽度等于nBitmaps乘以dxBitmap。

图9.6是一幅典型的在工具栏中使用的位图,位图中包含了15个按钮。由于工具栏按照位置来分隔并使用位图,所以位图中各按钮的位置必须严格按照尺寸等距离排列,而且位图中不同按钮位图的尺寸必须是相同的。



图9.6  工具栏使用的位图

除了使用自定义的位图以外,Comctl32.dll库文件中也提供一些通用的位图供工具栏使用。为了使用这组位图,可以在hBMInst参数中使用预定义的模块实例句柄HINST_COMMCTRL。

Comctl32.dll包含了两组可以使用的位图。第一组就是如图9.6所示的位图,可以在wBMID中指定IDB_STD_LARGE_COLOR(24×24像素)或IDB_STD_SMALL_COLOR(16×16像素)来引用它们。这组位图包括15个按钮,Windows.inc文件中已经为每个按钮的位置索引定义了预定义值,从左到右分别是STD_CUT,STD_COPY,STD_PASTE,STD_UNDO,STD_REDOW(不知道REDO后面为什么有个W),STD_DELETE,STD_FILENEW,STD_FILEOPEN,STD_FILESAVE,STD_PRINTPRE,STD_PROPERTIES,STD_HELP,STD_FIND,STD_REPLACE和STD_PRINT。

第二组位图可以在wBMID中使用IDB_VIEW_LARGE_COLOR或IDB_VIEW_SMALL_COLOR来引用它们,这个位图包含12个按钮图像,索引值0~11分别被预定义为VIEW_LARGEICONS,VIEW_SMALLICONS,VIEW_LIST,VIEW_DETAIL,VIEW_SORTNAME,VIEW_SORTSIZE,VIEW_SORTDATE,VIEW_SORTTYPE,VIEW _PARENTFOLDER,VIEW_NETCONNECT,VIEW_NETDISCONNECT和VIEW _NEWFOLDER,读者从字面上就可以想出这些位图究竟是什么样的。

参数dxButton和dyButton指定工具栏上按钮的尺寸,按钮的尺寸一般比按钮图像的尺寸要大一点。

剩余的3个参数lpButtons,iNumButtons和uStructSize用来定义工具栏上的按钮,函数根据它们给出的数据创建工具栏上的全部按钮。lpButtons参数指向一组按顺序排列的TBBUTTON结构,每个TBBUTTON结构定义一个按钮,TBBUTTON结构的排列顺序决定了按钮在工具栏上的排列顺序;iNumButtons参数指定工具栏上的按钮总数,也就是lpButtons指向的数据中包含的TBBUTTON结构的总数;uStructSize参数指明TBBUTTON结构的长度。

TBBUTTON结构的定义如下:

TBBUTTON STRUCT

  iBitmap     DWORD  ? ;按钮使用的位图编号

  idCommand DWORD ? ;按钮按下时在WM_COMMAND中使用的ID

  fsState   BYTE   ? ;按钮状态

  fsStyle   BYTE   ? ;按钮风格

  _wPad1     WORD ? ;

  dwData     DWORD ? ;自定义数据

  iString   DWORD ? ;按钮字符串索引

TBBUTTON ENDS

上面的结构定义取自MASM32软件包所附带的Windows.inc文件,但是Microsoft Win32 API手册中的结构定义并没有_wPad1字段,现在并没有资料判定Windows.inc中的定义是否正确,但这个定义在实际使用中并不会出错,所以本书中的例子沿用这个定义,这一点请读者注意。结构中各字段的含义如下。

● iBitmap——按钮使用的图像在wBMID 参数指定的位图中的位置索引。位置索引从0开始,也就是说第一个按钮图像的位置索引是0。

● idCommand——按下按钮以后,工具栏会向父窗口发送WM_COMMAND消息,这个字段指定消息附带的命令ID号,一般在这里指定与按钮对应的菜单项使用的ID。

● fsState——按钮的类型和初始状态,可以是下面取值的组合:

■ TBSTATE_CHECKED——按钮的类型是复选框按钮,并且按钮初始化为选中状态(即保持按下状态)。

■ TBSTATE_ENABLED——按钮被允许,如果不指定这个标志,按钮将显示为灰色,并且不会接收用户的动作。

■ TBSTATE_HIDDEN——隐藏状态,按钮不显示在工具栏上。

■ TBSTATE_INDETERMINATE——按钮处于灰化状态,但可以接收用户的动作。

■ TBSTATE_PRESSED——按钮处于按下状态。

■ TBSTATE_WRAP——在包含TBSTYLE_WRAPABLE风格的多行工具栏中,从此按钮开始换行。

● fsStyle——按钮风格,可以是下面取值的组合:

■ TBSTYLE_BUTTON——标准按钮。

■ TBSTYLE_CHECK——复选框按钮(按钮状态在按下和凸起之间切换)。

■ TBSTYLE_GROUP——指定复选框按钮的分组边界。

■ TBSTYLE_CHECKGROUP——TBSTYLE_CHECK风格和TBSTYLE_GROUP风格的组合。

■ TBSTYLE_SEP——按钮之间的分隔线。 

● dwData——用户自定义数据。设置后可以通过TB_GETBUTTON消息查询。

● iString——按钮标记的索引。

在例子程序中,使用模块句柄HINST_COMMCTRL和位图句柄IDB_STD_SMALL _COLOR来指定使用Comctl32.dll中的预定义位图,并预定义了16个TBBUTTON结构,存放在常量stToolbar开始的地址中。

当使用预定义位图的时候,函数自己知道位图的大小和按钮的大小,所以位图和按钮的尺寸参数都可以设置为0。函数的返回值是工具栏窗口的句柄,把它存放到hWinToolbar变量中以便在以后使用。

有关代码如下:

    ...

stToolbar   equ   this byte

TBBUTTON  

TBBUTTON  

TBBUTTON  

TBBUTTON  <0,0,TBSTATE_ENABLED,TBSTYLE_SEP,0,0,-1>

TBBUTTON  

    ...

NUM_BUTTONS   EQU   16

    ...

invoke  CreateToolbarEx,hWinMain,WS_VISIBLE or WS_CHILD or TBSTYLE_FLAT \

    or TBSTYLE_TOOLTIPS or CCS_ADJUSTABLE,ID_TOOLBAR,0,HINST_COMMCTRL,\

    IDB_STD_SMALL_COLOR,offset stToolbar,NUM_BUTTONS,\

    0,0,0,0,sizeof TBBUTTON

mov   hWinToolbar,eax

9.3.2  工具栏的控制消息

程序可以通过向工具栏控件发送消息来控制工具栏,工具栏的控制消息比较多,下面分类进行讨论。

1. 工具栏的创建和维护消息

如果使用CreateWindowEx函数来创建工具栏,那么创建的是一个空白的工具栏,还需要对工具栏进行初始化。初始化的工作包括指定位图、指定TBBUTTON结构长度和添加按钮。

指定工具栏使用的位图使用TB_ADDBITMAP消息:

invoke  SendMessage,hToolbar,TB_ADDBITMAP,nButtons,lptbab

wParam中的nButtons指定位图中包含的按钮图像数量,lptbab指向一个TBADDBITMAP结构,结构中定义了两个字段:位图资源的模块句柄和位图ID,这两个字段的定义方法和CreateToolbarEx函数的hBMInst和wBMID参数的定义方法是一样的。结构定义如下:

TBADDBITMAP STRUCT

  hInst   DWORD   ? ;包含位图的模块实例句柄

  nID   DWORD   ? ;位图资源的ID

TBADDBITMAP ENDS

指定了位图以后,需要发送TB_SETBITMAPSIZE和TB_SETBUTTONSIZE消息来指定按钮图像的大小和按钮的大小,这一步相当于指定CreateToolbarEx函数中使用的dxButton,dyButton,dxBitmap和dyBitmap参数。

宽度和高度参数分别由lParam参数的高16位和低16位指定:

invoke  SendMessage,hToolbar,TB_SETBITMAPSIZE,0,dwWidth + dwHeight shl 16

invoke  SendMessage,hToolbar,TB_SETBUTTONSIZE,0,dwWidth + dwHeight shl 16

CreateToolbarEx函数的最后一个参数uStructSize是为了向系统通知TBBUTTON的结构长度,如果使用CreateWindowEx函数来创建工具栏,那么这一步必须通过发送TB_BUTTONSTRUCTSIZE消息来完成:

invoke  SendMessage,hToolbar,TB_BUTTONSTRUCTSIZE,sizeof TBBUTTON,0

接下来可以使用TB_ADDBUTTONS消息来添加按钮,uNumButtons参数指定要添加的按钮数量,lpButtons参数指向一组TBBUTTON结构,结构的数量和uNumButtons参数相对应,在发送这个消息前必须先发送TB_BUTTONSTRUCTSIZE消息指定结构的长度:



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  获取工具栏状态的消息

消   息
 WParam
 Iparam
 说   明
 
TB_BUTTONCOUNT
 0
 0
 返回工具栏上按钮的数量
 
TB_GETBITMAP
 idButton
 0
 返回指定按钮的图像索引
 
TB_GETBUTTON
 iButton
 lpButton
 返回指定按钮的TBBUTTON结构
 
TB_GETROWS
 0
 0
 返回多行工具栏当前包含的行数
 
TB_GETITEMRECT
 iButton
 lpRect
 在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

  ...

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

 



9.3 使用工具栏(6)


2. 定制工具栏

定制功能是工具栏中最令人

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -