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

原创 2000年12月15日 08:59:00




--------------------------------------------------------------------------------

有关菜单和加速键

菜单是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实际上就是执行了菜单项“拷贝”。
菜单和加速键的编程是很简单的,初始化的部分你需要做以下事情:

取得程序的实例句柄(hInstance)
用LoadMenu装入菜单,得到菜单句柄
用LoadAccelerator装入加速键,得到加速键句柄
注册窗口类
创建窗口时在参数中制定菜单句柄
显示窗口
然后进入消息循环,在消息循环中用TranslateAccelerator来进行加速键的检测(详见源程序)
当窗口显示后,当一个菜单项或一个加速键被按下时,Windows向窗口过程发送WM_COMMAND消息,而当一个系统菜单中的菜单项被按下时,Windows 向窗口过程发送WM_SYSCOMMAND,菜单项命令的ID就包括在wParam的低16位中,在一般的编程中,如果我们不对系统菜单消息进行处理,那么只需在WM_COMMAND消息的处理中建立一段 .if/.elseif/.elseif .../.endif的语句对各个菜单命令ID进行处理就行了。

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

.386
.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使用。

 

Win32汇编之使用资源--菜单和加速键

///我们在使用软件时可以看到菜单、图标、版本信息等,它们是可执行文件的组成     部分也是Windows中的不同类型的资源。这些资源并不在源码的数据段中定义,     而是单独放在一个节区中,需...
  • u012869992
  • u012869992
  • 2014年08月10日 19:45
  • 577

Win32汇编教程五:菜单和加速键的使用

有关菜单和加速键菜单是Windows标准界面的最重要的组成部分,窗口的菜单条位于标题栏的下方,这个菜单通常被称为主菜单,列在主菜单下面的菜单项被称为下拉式菜单,或弹出式菜单、子菜单等,而在标题栏左边的...
  • zhangkala
  • zhangkala
  • 2008年11月26日 16:11
  • 599

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

2000年12月15日 08:59:00 ---------------------------------------------------------------------------...
  • softart
  • softart
  • 2007年10月27日 07:44
  • 236

Win32汇编--如何使用资源 [菜单和加速键]

使用资源 —— 菜单和加速键     主菜单,顶层菜单,弹出式菜单,子菜单,右键弹出式菜单,系统弹出式菜单。菜单中的菜单项有好几种,从资源定义的角度来看,分隔用的横线也是一个菜单项,除横线...
  • cyg0810
  • cyg0810
  • 2012年07月18日 10:56
  • 3070

WIN32汇编 菜单和加速键的使用

一.首先是菜单加速键资源文件: 有了资源文件,使得一个windows窗口更加有特点,更加丰富,刚开始编写资源文件真是废了好大劲,在用编译器的时候更是纠结,RadASM是一个集成的汇编工具,里面虽然自带...
  • qq_22642239
  • qq_22642239
  • 2016年03月21日 21:53
  • 549

Win32汇编--使用资源--菜单和加速键

使用资源 —— 菜单和加速键 主菜单,顶层菜单弹出式菜单,子菜单右键弹出式菜单系统弹出式菜单 菜单中的菜单项有好几种,从资源定义的角度来看,分隔用的横线也是一个菜单项,除横线外其他菜单项可以供用户选择...
  • laogaoAV
  • laogaoAV
  • 2013年01月26日 19:06
  • 930

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

本节的内容是上一节内容的扩展,所以示范的源程序是在上一节的基础上扩展的。 有关菜单和加速键     菜单是Windows标准界面的最重要的组成部分,窗口的菜单条位于标题栏的下方,这个菜单通常...
  • hjjj_122
  • hjjj_122
  • 2010年07月29日 00:30
  • 371

Win32的加速键与鼠标,系统菜单,资源加载

一 系统菜单   1 执行系统提供的窗口命令,例如最大化、关闭     等命令。本质上和普通菜单一样,所以我们也     可以在程序中使用这个菜单       2 系统菜单的使用    ...
  • zouyouliang1
  • zouyouliang1
  • 2015年03月26日 22:36
  • 584

Win32 SDK 创建加速键表。

加速键与菜单密切相关——都向用户提供一个应用程序的命令集的操作。通常情况下,用户依靠菜单来了解命令集合,在熟悉了应用程序后转而使用加速键。加速键提供比菜单更快、更直接的命令操作。虽然加速键通常产生菜单...
  • zhiweiyouzhishenghuo
  • zhiweiyouzhishenghuo
  • 2012年02月13日 17:35
  • 2195

Win32汇编基础教程

Win32汇编教程之一Win32汇编的环境和基础1.32位环境简介  在Dos下编汇编程序,我们可以管理系统的所有资源,我们可以改动系统中所有的内存,如自己改动内存控制块来分配内存,自己修改中断向量表...
  • t0nsha
  • t0nsha
  • 2008年03月27日 16:38
  • 2442
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Win32汇编教程五 菜单和加速键的使用
举报原因:
原因补充:

(最多只允许输入30个字)