上一题下一题
跳转到
 
 
  世界如此多姿,发展如此迅速,窥一斑未必还能知全豹。但正如万花筒一样,每一个管窥都色彩斑斓。  
 
 
  知识通道 | 学习首页 | 教师首页 | PK首页 | 知识创造首页 | 企业首页 | 登录
 
本文对应知识领域
Win32汇编教程五-菜单和加速键的使用
作者:未知 申领版权
2010年12月12日 共有 2189 次访问 【添加到收藏夹】 【我要附加题目
受欢迎度:

    
    Win32汇编教程五-菜单和加速键的使用
    
    本节的内容是上一节内容的扩展。
    
    有关菜单和加速键
    
    菜单是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使用。

    

 

相关新闻

testtest
上善制度的炼成
新时代呼唤管理理论创新——大卫�梯斯与动态能力理论
创业的不变逻辑
创新管理需要回答的5个问题
十一、弥离
十、转院
九、生机
八、传染
七、求血

您可能对这些感兴趣  

干货分享|10本最受国外孩子喜爱的英文词典——上
从孩子的表现看父母的缺点!请家长对号入座,看看你是哪一类?
20条制作PPT的视觉原则
培训简史:培训者必知的历史轨迹
广田丰管理培训生人才培养调查报告
第4讲 作为上司的职业经理
第3讲 作为同事的职业经理
第2讲 作为下属的职业经理
第1讲 培养经理人的管理素养
酒店前台新员工上岗培训计划

题目筛选器
日期:
类型:
状态:
得分: <=
分类:
作者:
职业:
关键字:
搜索

 
 
 
  焦点事件
 
  知识体系
 
  职业列表
 
 
  最热文章
 
 
  最多引用文章
 
 
  最新文章
 
 
 
 
网站介绍 | 广告服务 | 招聘信息 | 保护隐私权 | 免责条款 | 法律顾问 | 意见反馈
版权所有 不得转载
沪ICP备 10203777 号 联系电话:021-54428255
  帮助提示    
《我的太学》是一种全新的应用,您在操作中遇到疑问或者问题,请拨打电话13564659895,15921448526。
《我的太学》