WIN32汇编语言教程:第05章 使用资源 · 5.4 对话框(2)
脚本文件中除了定义图标以外,另外还定义了一个ID为1的对话框,对话框中有4个子窗口控件,分别是图标、文本、按钮和一个横线,按钮的ID为IDOK,其他的子窗口控件由于是静态控件,不会向对话框过程发送命令,所以ID就设置为−1,这些控件的具体用法将在后面的内容中详细介绍。
定义中还指定了一些可选属性,STYLE语句定义了对话框窗口的风格,CAPTION语句把标题定义为“对话框模板”,FONT语句指定了对话框使用的字体是大小为9的宋体。
对话框的位置为(50,50),大小为宽113单位、高64单位,读者可能已经注意到:这个对话框的大小好像比宽113像素、高64像素的窗口要大,事实上的确如此,这也正是大小是“单位”而不是“像素”的原因。对话框的位置、大小以及所有子窗口控件的度量单位是根据系统字体的大小来决定的,横向(x坐标和宽度)每单位为系统字符平均宽度的1/4,纵向(y坐标和高度)每单位为字符平均高度的1/8,由于系统字体的字符高度大致为宽度的两倍,所以虽然这种计算方法有些费解,但横向和纵向的数值在视觉上还是成比例的,但和以“像素”为单位在数值上肯定是不同的。如果读者一定要知道这个值换算成像素后是多少,那么可以用GetDialogBaseUnits函数来获取系统字体的高度和宽度再进行计算。
当一些英文版的软件在中文Windows上运行的时候,对话框中有些文本往往被砍掉了尾巴,原因就是这些程序是在英文Windows上调试的,文本框的尺寸是以英文Windows系统字符的大小来度量的,到了其他语言的Windows上后,系统字符的大小可能改变,对话框的大小也随着改变,结果就是原来刚好的宽度可能会变得不够,这也算是对话框尺寸度量方法的缺点吧!
使用文本编辑器直接书写对话框脚本定义不是很直观,所以在创建对话框资源时最好使用可视化的资源编辑器,如VC++或ResourceWorkshop等。
在子窗口控件的ID定义中有两个特殊的ID值——IDOK和IDCANCEL,在Resource.h中它们的值定义为1和2,IDOK是默认的“确定”ID,IDCANCEL是默认的“取消”ID。如果一个按钮的ID是IDOK,当焦点没有停留在其他按钮上的时候,在任何地方按下回车键就相当于按下了这个按钮,而按下Esc键的时候,就相当于按下了ID为IDCANCEL的按钮。
2. Tab停留位和组
对话框中可以定义多个子窗口控件,有的子窗口控件可以拥有输入焦点(如按钮、文本框与组合框等),有些则不能(如图标与文本等),当对话框中有多个允许拥有输入焦点的子窗口控件时(有WS_TABSTOP风格),用户可以用Tab键将输入焦点切换到下一个有WS_TABSTOP风格的子窗口控件上,也可以用Shift+Tab键切换到上一个,Tab键切换的顺序就叫做Tab停留位。
Tab停留位并不是系统根据子窗口控件的坐标位置自动排列的,而是按照子窗口控件在资源脚本文件中的定义顺序来排列的,所以读者在定义的时候最好根据子窗口控件的位置适当排列语句的先后,以免按动Tab键切换的时候焦点上下左右无规则地跳来跳去。如果使用可视化的资源编辑器,那么菜单中一般会有“Tab停留位”菜单项,在编辑完成后也要进到这个菜单项中设置一下,资源编辑器会根据设置调整rc文件中定义语句的先后顺序。
对话框中往往有一些排列在一起的同类子窗口控件,如几个单选钮,几个单选钮之间的选中标记是互斥的,在对话框的其他地方可能又有一组互斥的单选钮用来代表其他功能,在对话框中规定所有的单选钮都是互斥的显然不现实,解决的方法就是将不同的子窗口控件 “分组”,这就是“组”的含义。使用中可以选择一些子窗口控件定义WS_GROUP属性,两个有WS_GROUP属性的子窗口控件之间的所有子窗口控件同属同一组。
5.4.3 使用对话框
使用对话框的代码分为创建部分和对话框过程两个部分。先看Dialog.asm的源代码,再分析具体的使用过程,源代码如下:
.386 .model flat, stdcall option casemap :none ;############################################################### ; Include 文件定义 ;############################################################### include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib ;############################################################### ; Equ 等值定义 ;############################################################### ICO_MAIN equ 1000h ;图标 DLG_MAIN equ 1 ;############################################################### ; 数据段 ;############################################################### .data? hInstance dd ? ;############################################################### ; 代码段 ;############################################################### .code _ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam mov eax,wMsg .if eax == WM_CLOSE invoke EndDialog,hWnd,NULL .elseif eax == WM_INITDIALOG invoke LoadIcon,hInstance,ICO_MAIN invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax .elseif eax == WM_COMMAND mov eax,wParam .if ax == IDOK invoke EndDialog,hWnd,NULL .endif .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp ;############################################################### start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,hInstance,DLG_MAIN,\ NULL,offset _ProcDlgMain,NULL invoke ExitProcess,NULL ;############################################################### end start
读者可以发现,相对于普通窗口的使用,对话框的使用显得特别简单,最明显的区别在于主程序中的一大堆代码不见了,换成了一个DialogBoxParam语句。
1. 创建模态对话框
创建模态对话框的函数是DialogBoxParam,它的使用方法是:
invoke DialogBoxParam,hInstance,lpTemplateName,hWndParent,\ lpDialogFunc,dwInitParam