Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1760215
  • 博文数量: 290
  • 博客积分: 10653
  • 博客等级: 上将
  • 技术积分: 3178
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-24 23:08
文章存档

2013年(6)

2012年(15)

2011年(25)

2010年(86)

2009年(52)

2008年(66)

2007年(40)

分类:

2007-12-14 18:14:46

文件: tut08-1.zip
大小: 3KB
下载: 下载
文件: tut08-2.zip
大小: 3KB
下载: 下载
Tutorial 8: Menu

第八课:菜单

In this tutorial, we will learn how to incorporate a menu into our window.
Download the example 1 and example 2.

在这一课中,我们将要学习如何将一个菜单加到我们的窗口中。

Theory:

原理:

Menu is one of the most important components in your window. Menu presents a list of services a program offers to the user. The user doesn't have to read the manual included with the program to be able to use it, he can peruse the menu to get an overview of the capability of a particular program and start playing with it immediately. Since a menu is a tool to get the user up and running quickly, you should follow the standard. Succinctly put, the first two menu items should be File and Edit and the last should be Help. You can insert your own menu items between Edit and Help. If a menu item invokes a dialog box, you should append an ellipsis (...) to the menu string.

菜单在你的窗口中是最重要的一部分。当前菜单将一系列服务程序提供给用户使用。用户没有必要去阅读程序手册来了解如何使用这个应用程序,他只要细读一下所有的菜单项就能够对这个特殊的应用程序的功能有一个全面的了解并且可以立即开始使用它。因为菜单给用户程序提供了方便快捷的运行方式。所以当你在你的应用程序中加入菜单时应该遵循一般的标准。最简便的放置方式是:一开始的那两个菜单项应该是“文件”和“编辑”而最后一个是“帮助”。你能在“编辑”和“帮助”之间插入你自己的菜单项。如果一个菜单项调用一个对话框,你应该为这个菜单项的名字追加一个省略号(。。。 )
Menu is a kind of resource. There are several kinds of resources such as dialog box, string table, icon, bitmap, menu etc. Resources are described in a separated file called a resource file which normally has .rc extension. You then combine the resources with the source code during the link stage. The final product is an executable file which contains both instructions and resources.

菜单是一类资源。 这里有几种类型的资源例如:对话框,字符串表,图表,位图,菜单等等。资源通常被说明在一个分离的文件中,被调用的资源文件通常以.rc为后缀。你可以在连接程序的时候将这些资源和程序源代码组合在一起。 

最后的产物是一个含有指令和资源的可执行文件。 
You can write resource scripts using any text editor. They're composed of phrases which describe the appearances and other attributes of the resources used in a particular program Although you can write resource scripts with a text editor, it's rather cumbersome. A better alternative is to use a resource editor which lets you visually design resources with ease. Resource editors are usually included in compiler packages such as Visual C++, Borland C++, etc.

你能用任何文本编辑软件来写资源脚本。 它们是用来描述在某特定程序中的资源的外部特征和属性的短语组合。 虽然你能在文本编辑中写资源脚本,但它是相当麻烦的。 一个更好的方案是用资源编辑器,它容易让你设计出一个可视的资源。 资源编辑器通常被包含在编译程序包之中,如:visual c++ ,Borland C ++ 等。

 You describe a menu resource like this:

 你应该像这样来描述一个菜单资源:
 

MyMenu  MENU
{
   [menu list here]
}

C programmers may recognize that it is similar to declaring a structure. MyMenu being a menu name followed by MENU keyword and menu list within curly brackets. Alternatively, you can use BEGIN and END instead of the curly brackets if you wish. This syntax is more palatable to Pascal programmers.

 

C程序设计员可以认为它和声明一个结构有相似之处。MyMenu是菜单资源的名字,跟随在MENU关键字后面波形括号中的是菜单项。作为选择,如果你想,你还可以用BEGINEND来替代这个波形括号。这种句法对PASCAL的程序员来说更称心。


Menu list can be either MENUITEM or POPUP statement.

菜单列表中的菜单项可以用MENUITEM POPUP语句来声明。
MENUITEM statement defines a menu bar which doesn't invoke a popup menu when selected.The syntax is as follows:

 

MENUITEM "&text", ID [,options]

 

MENUITEM语句定义一个菜单项,当它被选择时并不调用弹出式菜单。 句法如下:

 

 MENUITEM "&text", ID [,options]

 

It begins by MENUITEM keyword followed by the text you want to use as menu bar string. Note the ampersand. It causes the character that follows it to be underlined. Following the text string is the ID of the menu item. The ID is a number that will be used to identify the menu item in the message sent to the window procedure when the menu item is selected. As such, each menu ID must be unique among themselves.

首先,通过在关键字MENUITEM后跟随一文本用来作为你想使用的菜单项字串. 注意这个符号(&),它后面的第一个字符将被加上下划线.

文本字串后面的 是这个菜单项的ID.ID值是一个数字,当菜单项被选择时,它作为消息中的菜单项标识传递给窗口过程.同样的, 没一个菜单项的ID值都必须是唯一的.

 

Options are optional. Available options are as follows:

Options是可选项,可用的选项如下所示: 

 

 GRAYED  The menu item is inactive, and it does not generate a WM_COMMAND message. The text is grayed.

GRAYED    表该菜单项处于非激活状态,   即当其被选中时不会产生 WM_COMMAND消息。该菜单项显示为灰色.

 

  • INACTIVE The menu item is inactive, and it does not generate a WM_COMMAND message. The text is displayed normally.

INACTIVE    表该菜单项处于非激活状态,   即当其被选中时不会产生 WM_COMMAND消息。该菜单以正常颜色显示

  • MENUBREAK  This item and the following items appear on a new line of the menu.

MENUBREAK  这个菜单项和以后的菜单项列到新的一列中

  • HELP  This item and the following items are right-justified.

这个菜单项和以后的菜单项右对齐.

You can use one of the above option or combine them with "or" operator. Beware that INACTIVE and GRAYED cannot be combined together.

你能用一个或多个上面的选项,当用到多个选项时,用OR操作将它们组合.

注意 INACTIVE GRAYED不能被组合在一起.

 

POPUP statement has the following syntax:

弹出式的菜单句法如下: 
  POPUP "&text" [,options]
{
  [menu list]
}

POPUP statement defines a menu bar that, when selected, drops down a list of menu items in a small popup window. The menu list can be a MENUITEM or POPUP statement. There's a special kind of MENUITEM statement, MENUITEM SEPARATOR, which will draw a horizontal line in the popup window.

POPUP定义了这样一个菜单项,当它被选择时,弹出一个小窗口这个小窗口中包含一系列菜单项.这些菜单项能被MENUITEM POPUP声明,这里有一种特别的MENUITEM语句,MENUITEM SEPARATOR ,它将在弹出式窗口中画一条水平线.


The next step after you are finished with the menu resource script is to reference it in your program.

在你完成菜单资源脚本的定义后,下一步的工作就是在程序中引用它.
You can do this in two different places in your program.

你能用如下方式在程序中的两个不同的地方使用它:

  • In lpszMenuName member of WNDCLASSEX structure. Say, if you have a menu named "FirstMenu", you can assigned the menu to your window like this:

WNDCLASSEX结构成员变量lpszMenuName中。看,如果你有一个菜单的名字是“FirstMenu“你能像这样把这个菜单分配在你的窗口中:

.DATA

MenuName  db "FirstMenu",0

...........................
...........................
.CODE

...........................
mov   wc.lpszMenuName, OFFSET MenuName


...........................

  • In menu handle parameter of CreateWindowEx like this:

 在作为CreateWindowEx函数的参数的菜单句柄中像这样使用: 

.DATA

MenuName  db "FirstMenu",0
hMenu HMENU ?

...........................
...........................
.CODE

...........................
invoke LoadMenu, hInst, OFFSET MenuName
mov   hMenu, eax
invoke CreateWindowEx,NULL,OFFSET ClsName,\
            OFFSET Caption, WS_OVERLAPPEDWINDOW,\
            CW_USEDEFAULT,CW_USEDEFAULT,\
            CW_USEDEFAULT,CW_USEDEFAULT,\
            NULL,\
           hMenu,\
            hInst,\
            NULL\
...........................

So you may ask, what's the difference between these two methods?
When you reference the menu in the WNDCLASSEX structure, the menu becomes the "default" menu for the window class. Every window of that class will have the same menu.

如此,你可能会问,为什么要定义两种不同的引用方法? 

当你在WNDCLASSEX结构中引用这个菜单时,这个菜单就变成窗口类的默认菜单。

每一个基于这个类创建的窗口都将有着相同的菜单。 
If you want each window created from the same class to have different menus, you must choose the second form. In this case, any window that is passed a menu handle in its CreateWindowEx function will have a menu that "overrides" the default menu defined in the WNDCLASSEX structure.
如果你想在基于同于一个窗口类创建的不同窗口中拥有不同的菜单,你必须用第二种形式。          既然这样,任何窗口只要传递一个菜单句柄
CreateWindowEx函数,它将忽略那个在WNDCLASSEX结构中定义的默认菜单。

 

Next we will examine how a menu notifies the window procedure when the user selects a menu item.

When the user selects a menu item, the window procedure will receive a WM_COMMAND message. The low word of wParam contains the menu ID of the selected menu item.

 

下一步,我们将分析当用户选中一个菜单项时,这个菜单项是如何通知窗口过程的。当用户选择一个菜单项时,窗口过程将接收到一个WM_COMMAND消息。消息中的低字节参数 wParam包含这个被选中的菜单项的ID 值。


Now we have sufficient information to create and use a menu. Let's do it.

 现在,我们已经有充分的信息来创建和使用一个菜单,让我们试一试。 

Example:

例子:

The first example shows how to create and use a menu by specifying the menu name in the window class.

第一个例子将显示通过在窗口类中指定一菜单名的方式来创建和使用这个菜单。

.386
.model flat,stdcall
option casemap:none

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
ClassName db "SimpleWinClass",0
AppName  db "Our First Window",0
MenuName db "FirstMenu",0                ; The name of our menu in the resource file.
Test_string db "You selected Test menu item",0
Hello_string db "Hello, my friend",0
Goodbye_string db "See you again, bye",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?

.const
IDM_TEST equ 1                    ; Menu IDs
IDM_HELLO equ 2
IDM_GOODBYE equ 3
IDM_EXIT equ 4

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax

    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,OFFSET MenuName        ; Put our menu name here
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
           hInst,NULL
    mov   hwnd,eax
    invoke ShowWindow, hwnd,SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .WHILE TRUE
                invoke GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                invoke DispatchMessage, ADDR msg
    .ENDW
    mov     eax,msg.wParam
    ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF ax==IDM_TEST
            invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
        .ELSEIF ax==IDM_HELLO
            invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
        .ELSEIF ax==IDM_GOODBYE
            invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
        .ELSE
            invoke DestroyWindow,hWnd
        .ENDIF
    .ELSE
        invoke DefWindowProc,hWnd,uMsg,wParam,lParam
        ret
    .ENDIF
    xor    eax,eax
    ret
WndProc endp
end start
**************************************************************************************************************************

Menu.rc

**************************************************************************************************************************

#define IDM_TEST 1
#define IDM_HELLO 2
#define IDM_GOODBYE 3
#define IDM_EXIT 4

FirstMenu MENU
{
 POPUP "&PopUp"
        {
         MENUITEM "&Say Hello",IDM_HELLO
         MENUITEM "Say &GoodBye", IDM_GOODBYE
         MENUITEM SEPARATOR
         MENUITEM "E&xit",IDM_EXIT
        }
 MENUITEM "&Test", IDM_TEST
}
 

Analysis:

分析:

Let's analyze the resource file first.

首先,让我们分析一下资源文件. 
  #define IDM_TEST 1                /* equal to IDM_TEST equ 1*/
#define IDM_HELLO 2
#define IDM_GOODBYE 3
#define IDM_EXIT 4
 The above lines define the menu IDs used by the menu script. You can assign any value to the ID as long as the value is unique in the menu.

上面这些行用来声明在菜单资源脚本中使用的ID值。你能给菜单项的ID分配任何值只要这些值在菜单中是唯一的。 

FirstMenu MENU

Declare your menu with MENU keyword.

MENU关键字声明你的菜单。

 POPUP "&PopUp"
        {
         MENUITEM "&Say Hello",IDM_HELLO
         MENUITEM "Say &GoodBye", IDM_GOODBYE
         MENUITEM SEPARATOR
         MENUITEM "E&xit",IDM_EXIT
        }

Define a popup menu with four menu items, the third one is a menu separator.

定义了一个有四个菜单项的弹出式菜单,第三个菜单是分隔符。 

 MENUITEM "&Test", IDM_TEST

Define a menu bar in the main menu.
Next we will examine the source code.

定义一个菜单项在主菜单中。

下面我们将分析源代码。 
 

MenuName db "FirstMenu",0                ; The name of our menu in the resource file.
Test_string db "You selected Test menu item",0
Hello_string db "Hello, my friend",0
Goodbye_string db "See you again, bye",0


 MenuName is the name of the menu in the resource file. Note that you can define more than one menu in the resource file so you must specify which menu you want to use. The remaining three lines define the text strings to be displayed in message boxes that are invoked when the appropriate menu item is selected by the user.


 MenuName
是指在资源文件中的菜单名。注意,你能在资源文件中定义不止一个的菜单所以你必须指出那一个菜单是你想使用的。 剩下的三行定义的是当用户选择了适当的菜单项时在消息框中显示的字符串文本。


  IDM_TEST equ 1                    ; Menu IDs
IDM_HELLO equ 2
IDM_GOODBYE equ 3
IDM_EXIT equ 4


 Define menu IDs for use in the window procedure. These values MUST be identical to those defined in the resource file.

定义在窗口过程中使用的菜单项ID值。这些值必须同定义在资源文件中的值一样。

.ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .IF ax==IDM_TEST
            invoke MessageBox,NULL,ADDR Test_string,OFFSET AppName,MB_OK
        .ELSEIF ax==IDM_HELLO
            invoke MessageBox, NULL,ADDR Hello_string, OFFSET AppName,MB_OK
        .ELSEIF ax==IDM_GOODBYE
            invoke MessageBox,NULL,ADDR Goodbye_string, OFFSET AppName, MB_OK
        .ELSE
            invoke DestroyWindow,hWnd
        .ENDIF

 

 

In the window procedure, we process WM_COMMAND messages. When the user selects a menu item, the menu ID of that menu item is sended to the window procedure in the low word of wParam along with the WM_COMMAND message. So when we store the value of wParam in eax, we compare the value in ax to the menu IDs we defined previously and act accordingly. In the first three cases, when the user selects Test, Say Hello, and Say GoodBye menu items, we just display a text string in a message box.
If the user selects Exit menu item, we call DestroyWindow with the handle of our window as its parameter which will close our window.
As you can see, specifying menu name in a window class is quite easy and straightforward. However you can also use an alternate method to load a menu in your window. I won't show the entire source code here. The resource file is the same in both methods. There are some minor changes in the source file which I 'll show below.

我们在窗口过程中处理WM_COMMAND消息。当用户选择一个菜单项时,这个菜单项的ID被存贮在WM_COMMAND消息的低位字wParam中并传递给窗口过程 。所以我们用eax存储这个参数。(wparam)我们用在ax中的值来和我们以前定义的ID值比较并且回应它。(消息处理代码)在第一个例子中, 当用户选择了testsay hello say goodbye 菜单项时。我们仅在消息框中显示一字符。

如果用户选择的是exit菜单项,我们将用我们的窗口句柄作为DestroyWindow 的参数并调用这个函数来关闭我们的窗口。

如你所见,在窗口类中指定一个菜单名不仅是非常简单的而且更为直接。然而,你还能用另外一种方法来在你的窗口中装载一个菜单。我不想在这里展示所有的源代码。两种方法的资源文件是一样的,它们只是在源文件中有较小的一点改变。下面是源文件。
 

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hMenu HMENU ?                    ; handle of our menu
 Define a variable of type HMENU to store our menu handle.

定义一个句柄变量用来存储我们的菜单句柄。

        invoke LoadMenu, hInst, OFFSET MenuName
        mov    hMenu,eax
        INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,\
           hInst,NULL

Before calling CreateWindowEx, we call LoadMenu with the instance handle and a pointer to the name of our menu. LoadMenu returns the handle of our menu in the resource file which we pass to CreateWindowEx

在调用CreateWindowEx之前,我们用实例句柄和指向我们菜单名的指针作为LoadMenu的参数来调用它。loadMenu返回我们在资源文件中定义的菜单句柄并作为参数传递给CreatewindowEx 函数。


This article come from Iczelion's asm page,

风向改变翻译于 07年12.14日 

 

阅读(1603) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2008-06-24 21:12:40

我是win32编程的初学者,在调试该程序时, 并没有出现菜单 请帮帮忙.说一下该怎样处理 我是直接拷贝的 小弟在这里先说声谢谢了!!!!!