您的位置:首页 > 其它

Win32汇编教程5-菜单和加速键的使用

2010-07-29 00:30 465 查看
本节的内容是上一节内容的扩展,所以示范的源程序是在上一节的基础上扩展的。

有关菜单和加速键

菜单是Windows标准界面的最重要的组成部分,窗口的菜单条位于标题栏的下方,这个菜单通常被称为主菜单,列在主菜单下面的菜单项被称为下拉式菜单,
或弹出式菜单、子菜单等,而在标题栏左边的图标上点击也会弹出一个菜单,叫做系统菜单。加速键实际上是菜单项的快捷键,应用程序常在菜单项的右边标出激活
这个菜单项的快捷键,这就是加速键。菜单的结构是可嵌套的,也就是说,你可以在选择一个菜单项时弹出另一个菜单。菜单项的种类有正常的、被禁用的、灰化
的、水平分隔线等。本节的示范程序演示了各种类型的菜单:你可以在主菜单中看到正常的和禁用的、灰化的菜单,可以用右键单击窗口的任一部分弹出一个“弹出
式菜单”,也可以看到我在系统菜单中添加了几项新的内容。

在编程的处理中,菜单是在资源文件中定义的(当然,你可以不用资源文件,而在程序中用AppendMenu一项一项的添加,但使用资源文件无疑是最简单的
办法),然后在程序中用LoadMenu来获得菜单句柄再使用。在资源文件中定义菜单的语法如下:

菜单ID	menu	discardable

BEGIN

popup	"主菜单项一"

BEGIN

menuitem	"弹出式菜单项一",	命令ID	[,OPTION]

menuitem	"弹出式菜单项二",	命令ID	[,OPTION]

menuitem	separator

menuitem	"弹出式菜单项三",	命令ID	[,OPTION]

...

END

popup	"主菜单项二"

BEGIN

menuitem	"弹出式菜单项一",	命令ID	[,OPTION]

menuitem	"弹出式菜单项二",	命令ID	[,OPTION]

menuitem	"弹出式菜单项三",	命令ID	[,OPTION]

...

popup		"嵌套的菜单项"

BEGIN

menuitem	"弹出式菜单项一",	命令ID	[,OPTION]

menuitem	"弹出式菜单项二",	命令ID	[,OPTION]

menuitem	"弹出式菜单项三",	命令ID	[,OPTION]

...

END

END

...

END


菜单ID就是我们在程序中用LoadMenu装入菜单用到的资源编号,menuitem separator
定义了分隔菜单项用的水平线,菜单项定义中的option是属性,如GRAYED是灰化的,INACTIVE是被禁用的等等。而加速键实际上就是定义了对
应于各个菜单项的热键,定义方法如下:

加速键ID	accelerators

BEGIN

VK_F1,	对应的菜单命令ID,	VIRTKEY

VK_F2,	对应的菜单命令ID,	VIRTKEY

...

"A",	对应的菜单命令ID,	VIRTKEY,CONTROL

"B",	对应的菜单命令ID,	VIRTKEY,CONTROL

END


其中,加速键ID是我们在程序中用LoadAccelerator装入加速键的资源编号,下面的每一项定义了一个键,VK_F1表示用F1,“A”表示键
A,下面的VIRTKEY是必需的,再下面的CONTROL“或SHIFT、ALT”表示用CONTROL键组合,也就是说,如果你定义
了:"C",IDM_COPY,VIRTKEY,CONTROL 而且在菜单定义中定义了 menuitem
"拷贝",IDM_COPY,那么,你在程序中按下Ctrl-C实际上就是执行了菜单项“拷贝”。

菜单和加速键的编程是很简单的,初始化的部分你需要做以下事情:

1.取得程序的实例句柄(hInstance)

2.用LoadMenu装入菜单,得到菜单句柄

3.用LoadAccelerator装入加速键,得到加速键句柄

4.注册窗口类

5.创建窗口时在参数中制定菜单句柄

6.显示窗口

7.然后进入消息循环,在消息循环中用TranslateAccelerator来进行加速键的检测(详见源程序)

当窗口显示后,当一个菜单项或一个加速键被按下时,Windows向窗口过程发送WM_COMMAND消息,而当一个系统菜单中的菜单项被按下
时,Windows
向窗口过程发送WM_SYSCOMMAND,菜单项命令的ID就包括在wParam的低16位中,在一般的编程中,如果我们不对系统菜单消息进行处理,那
么只需在WM_COMMAND消息的处理中建立一段 .if/.elseif/.elseif
.../.endif的语句对各个菜单命令ID进行处理就行了。

使用菜单和加速键的源程序

.386

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	Programmed by 罗云彬, bigluo@telekbird.com.cn

;	Website: http://www.win32asm.com.cn 
;	LuoYunBin's Win32 ASM page (罗云彬的编程乐园)

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.model flat, stdcall

option casemap :none   ; case sensitive

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	Include 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include		windows.inc

include		user32.inc

include		kernel32.inc

include		comctl32.inc

include		comdlg32.inc

include		shell32.inc

include		gdi32.inc

includelib	user32.lib

includelib	kernel32.lib

includelib	comctl32.lib

includelib	comdlg32.lib

includelib	shell32.lib

includelib	gdi32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	Equ 数据

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

IDI_MAIN	equ		1000		;icon

IDA_MAIN	equ		2000		;Accelerator

IDM_MAIN	equ		4000

IDM_OPEN	equ		4101

IDM_OPTION	equ		4102

IDM_EXIT	equ		4103

IDM_SETFONT	equ		4201

IDM_SETCOLOR	equ		4202

IDM_FIND	equ		4203

IDM_FINDPREV	equ		4204

IDM_FINDNEXT	equ		4205

IDM_TOOLBAR	equ		4206

IDM_TOOLBARTEXT	equ		4207

IDM_INPUTBAR	equ		4208

IDM_STATUSBAR	equ		4209

IDM_HELP	equ		4301

IDM_ABOUT	equ		4302

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data?

hIcon		dd		?

hInstance	dd		?

hWinMain	dd		?

hMenu		dd		?

hSubMenu	dd		?

szBuffer	db	256 dup	(?)

dwFlag		dd		?

;********************************************************************

;	标志位定义

F_TOOLBAR	equ	00000001b

F_TOOLBARTEXT	equ	00000010b

F_INPUTBAR	equ	00000100b

F_STATUSBAR	equ	00001000b

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	数据段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.data

szClassName	db	"Menu Example",0

szCaptionMain	db	'菜单应用示例',0

szMenuHelp	db	"帮助主题(&H)",0

szMenuAbout	db	"关于本程序(&A)...",0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	代码段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

.code

include		Debug.asm

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	程序开始

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

call	_WinMain

invoke	ExitProcess,NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	主窗口程序

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_WinMain	proc

local	@stWcMain:WNDCLASSEX

local	@stMsg:MSG

local	@hAccelerator

invoke	InitCommonControls

invoke	GetModuleHandle,NULL

mov	hInstance,eax

invoke	LoadIcon,hInstance,IDI_MAIN

mov	hIcon,eax

invoke	LoadMenu,hInstance,IDM_MAIN

mov	hMenu,eax

;*************** 注册窗口类 *****************************************

invoke	LoadCursor,0,IDC_ARROW

mov	@stWcMain.hCursor,eax

mov	@stWcMain.cbSize,sizeof WNDCLASSEX

mov	@stWcMain.hIconSm,0

mov	@stWcMain.style,CS_HREDRAW or CS_VREDRAW

mov	@stWcMain.lpfnWndProc,offset WndMainProc

mov	@stWcMain.cbClsExtra,0

mov	@stWcMain.cbWndExtra,0

mov	eax,hInstance

mov	@stWcMain.hInstance,eax

mov	@stWcMain.hIcon,0

mov	@stWcMain.hbrBackground,COLOR_WINDOW + 1

mov	@stWcMain.lpszClassName,offset szClassName

mov	@stWcMain.lpszMenuName,0

invoke	RegisterClassEx,addr @stWcMain

;*************** 建立输出窗口 ***************************************

invoke	CreateWindowEx,WS_EX_CLIENTEDGE,/

offset szClassName,offset szCaptionMain,/

WS_OVERLAPPEDWINDOW OR WS_VSCROLL OR WS_HSCROLL,/

100,100,550,300,/

NULL,hMenu,hInstance,NULL

invoke	ShowWindow,hWinMain,SW_SHOWNORMAL

invoke	UpdateWindow,hWinMain

;*************** 消息循环 *******************************************

invoke	LoadAccelerators,hInstance,IDA_MAIN

mov	@hAccelerator,eax

.while	TRUE

invoke	GetMessage,addr	@stMsg,NULL,0,0

.break	.if eax	== 0

invoke	TranslateAccelerator,hWinMain,@hAccelerator,addr @stMsg

.if	eax == 0

invoke	TranslateMessage,addr @stMsg

invoke	DispatchMessage,addr @stMsg

.endif

.endw

ret

_WinMain	endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

WndMainProc	proc	uses ebx edi esi, /

hWnd:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

local	@stPos:POINT

mov	eax,uMsg

.if	eax ==	WM_CREATE

mov	eax,hWnd

mov	hWinMain,eax

call	_Init

;********************************************************************

.elseif	eax ==	WM_COMMAND

.if	lParam == 0

mov	eax,wParam

movzx	eax,ax

.if	eax ==	IDM_EXIT

call	_Quit

.elseif	eax ==	IDM_TOOLBAR

xor	dwFlag,F_TOOLBAR

call	_MenuStatus

.elseif	eax ==	IDM_TOOLBARTEXT

xor	dwFlag,F_TOOLBARTEXT

call	_MenuStatus

.elseif	eax ==	IDM_INPUTBAR

xor	dwFlag,F_INPUTBAR

call	_MenuStatus

.elseif	eax ==	IDM_STATUSBAR

xor	dwFlag,F_STATUSBAR

call	_MenuStatus

.else

_Debug	"菜单命令","命令ID",eax

.endif

.endif

;********************************************************************

.elseif	eax == WM_SYSCOMMAND

mov	eax,wParam

movzx	eax,ax

.if	eax == IDM_HELP || eax == IDM_ABOUT

_Debug	"菜单命令","命令ID",eax

.else

invoke	DefWindowProc,hWnd,uMsg,wParam,lParam

ret

.endif

;********************************************************************

;	按下右键时弹出一个POPUP菜单

;********************************************************************

.elseif eax == WM_RBUTTONDOWN

invoke	GetCursorPos,addr @stPos

invoke	TrackPopupMenu,hSubMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,NULL,hWnd,NULL

;********************************************************************

.elseif	eax ==	WM_CLOSE

call	_Quit

;********************************************************************

.else

invoke	DefWindowProc,hWnd,uMsg,wParam,lParam

ret

.endif

;********************************************************************

;	注意:WndProc 处理 Windows 消息后,必须在 Eax 中返回 0

;	但是由 DefWindowProc 处理后的返回值不能改变,否则窗口

;	将无法显示!

;********************************************************************

xor	eax,eax

ret

WndMainProc	endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;	主窗口控制子程序

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_Init		proc

local	@hSysMenu

invoke	SendMessage,hWinMain,WM_SETICON,ICON_SMALL,hIcon

;********************************************************************

;	POPUP菜单要用到子菜单才能实现

;********************************************************************

invoke	GetSubMenu,hMenu,1

mov	hSubMenu,eax

call	_MenuStatus

;********************************************************************

;	在系统菜单中添加菜单项

;********************************************************************

invoke	GetSystemMenu,hWinMain,FALSE

mov	@hSysMenu,eax

invoke	AppendMenu,@hSysMenu,MF_SEPARATOR,0,NULL

invoke	AppendMenu,@hSysMenu,MF_STRING,IDM_HELP,offset szMenuHelp

invoke	AppendMenu,@hSysMenu,MF_STRING,IDM_ABOUT,offset szMenuAbout

ret

_Init		endp

;********************************************************************

;	根据标志位设置相应菜单项的状态

;********************************************************************

_MenuStatus	proc

test	dwFlag,F_INPUTBAR

.if	ZERO?

invoke	CheckMenuItem,hMenu,IDM_INPUTBAR,MF_UNCHECKED

.else

invoke	CheckMenuItem,hMenu,IDM_INPUTBAR,MF_CHECKED

.endif

test	dwFlag,F_TOOLBAR

.if	ZERO?

invoke	CheckMenuItem,hMenu,IDM_TOOLBAR,MF_UNCHECKED

.else

invoke	CheckMenuItem,hMenu,IDM_TOOLBAR,MF_CHECKED

.endif

test	dwFlag,F_TOOLBARTEXT

.if	ZERO?

invoke	CheckMenuItem,hMenu,IDM_TOOLBARTEXT,MF_UNCHECKED

.else

invoke	CheckMenuItem,hMenu,IDM_TOOLBARTEXT,MF_CHECKED

.endif

test	dwFlag,F_STATUSBAR

.if	ZERO?

invoke	CheckMenuItem,hMenu,IDM_STATUSBAR,MF_UNCHECKED

.else

invoke	CheckMenuItem,hMenu,IDM_STATUSBAR,MF_CHECKED

.endif

ret

_MenuStatus	endp

;********************************************************************

_Quit		proc

invoke	DestroyWindow,hWinMain

invoke PostQuitMessage,NULL

ret

_Quit		endp

;********************************************************************

end	start


程序的分析

让我们来简单分析一下这个程序,首先这个程序和上一节的最简单的窗口程序的不同之处就是消息循环,如下:

.while	TRUE

invoke	GetMessage,addr	@stMsg,NULL,0,0

.break	.if eax	== 0

invoke	TranslateAccelerator,hWinMain,@hAccelerator,addr @stMsg

.if	eax == 0

invoke	TranslateMessage,addr @stMsg

invoke	DispatchMessage,addr @stMsg

.endif

.endw


在循环中的TranslateAccelerator用来确定存放在MSG结构中的消息是不是键盘消息,如果是,它查找句柄@hAccelerator对
应的加速键表,如果找到了一个匹配项,那么它将用命令ID向窗口发送WM_COMMAND消息,同时返回非0值,这时候表示消息已经被处理,不用再调用下
面的TranslateMessage 和 DispatchMessage 了,如果不是,那么它将返回0,消息循环继续。

另外,要说明的是弹出式菜单,在程序中我们响应WM_RBUTTONDOWN消息对按下右键进行处理,
然后调用GetCursorPos取得当前鼠标坐标,然后使用TrackPopupMenu在鼠标位置上弹出一个菜单,但是在资源文件中,“弹出式菜单”
是无法直接定义的,所以在初始化部分,我们使用GetSubMenu 取出弹出式子菜单的句柄供TrackPopupMenu使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: