windowsSDK 菜单资源浅谈

这几天在看菜单,今天自己动手写了一下,出现了一些错误。


首先我先自己简单的写了一个只包含菜单资源的文件:

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

//TCHAR szAppName[] = TEXT ("ownmenu") ;      (改进后加的代码)
TCHAR MenuName[] = TEXT("IDR_MENU1");

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     HWND     hwnd ;
     MSG      msg ;
     WNDCLASS wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
   //wndclass.lpszMenuName  = MenuName ;        (改进后加入的代码)                        
     wndclass.lpszMenuName  = szAppName;       //程序名称和菜单名称是一样的
     wndclass.lpszClassName = szAppName ;
     
     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName, TEXT ("Menu Demonstration"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
     HMENU      hMenu ;                         //定义了菜单句柄
     
     switch (message)
     {
     case WM_COMMAND:                           //选择一项被启用的菜单
          hMenu = GetMenu (hwnd) ;
          
          switch (LOWORD (wParam))              //里面包含的是菜单ID
          {
		  case ID_FILE_NEW:
			  MessageBox(hwnd, TEXT("CREATE A NEW FILE"), TEXT("hello"), MB_OK);
			  break;
		  case ID_FILE_EXIT:
			  SendMessage(hwnd, WM_CLOSE, 0, 0);
			  break;

          }
          break ;
          return 0;
               
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

写完以后我新建一个资源文件,然后在里面添加菜单资源。

接下来我编辑菜单如下图所示:windowsSDK 菜单资源浅谈_第1张图片

注意一下系统默认的菜单ID是  IDR_MENU1

我创建的4个popup的初始ID是ID_FILE_NEW40001

                                                      ID_FILE_OPEN40002

                                                      ID_FILE_SAVE40003

                                                      ID_FILE_EXIT

然后我尝试更改ID,把数字给去掉

                                                      ID_FILE_NEW

                                                      ID_FILE_OPEN

                                                      ID_FILE_SAVE

                                                      ID_FILE_EXIT

一编译,发现错误提示说         ID_FILE_NEW

                                                      ID_FILE_OPEN

                                                      ID_FILE_SAVE

全部找不到。


然后我去resource.h的文件里面去找,发现宏定义里面竟然没有把我改好以后的ID变掉,还是

                                                      ID_FILE_NEW40001

                                                      ID_FILE_OPEN40002

                                                      ID_FILE_SAVE40003

那么我心里想,就手工把后面的数字去掉吧   -_-


然后再次编译,错误提示说   ID_FILE_NEW    redefinition

                                                    ID_FILE_OPEN    redefinition

                                                    ID_FILE_SAVE    redefinition

这就奇怪了,为什么会说    重定义错误呢?

我在网上查了写有关redefinition 错误的资料  

redefinition的错误
原因一般是由于你调用的函数没有在前面声明,而系统会默认为int型
而在后面你可能又写了函数体,但定义类型又不是int,所以报redefinition的错误
解决办法是恢复h文件,或在文件前面添加报redefinition错误的函数的声明

最后再看了下代码,终于发现问题所在了。

wndclass.lpszMenuName  = szAppName;    

在定义窗口类的时候,我把菜单的名字和窗口的名字写做一样了,其实系统默认的窗口名字是IDR_MENU1

所以在编译资源的时候,.h文件根本就不会改变!

找到原因了,现在我有两种改进的方法:

1.将wndclass.lpszMenuName  命名为系统默认的 IDR_MENU1

2. 将菜单名称变成ownmenu

但是依旧要注意,当你每次改变了菜单ID的时候,最好同时检查resource.h里面有没有发生改变,否则就会出现我上面说的错误哦!!~~~


  下面再看看菜单引用的3种方法吧,其实自己一开始的时候是把下面的第一种方法和第二种方法搞混了,才会导致上面的错误。

第一种方法:
在注册窗口类的时候就指定要菜单,在WNDCLASSEX结构体的成员lpszMenuName中,假设我把引入菜单的叫做”MenuDemo”,
那么就可以这样引用:
TCHAR szAppName[] = TEXT (“MenuDemo”)
//code
wndclass.lpszMenuName  = szAppName ;

上面这个例子是把程序名称和菜单名称做了相同的引用,用这种方法的话比较方便,比如在你的程序里面还有图标,声音或者其他的一些自定义资源的话,这种方法看起来就显得简单多了。

在这里就指定了你要的菜单,在窗口建立之前就已经包含在窗口类中了,建立窗口的时候直接就出来菜单。这种方法比较简单,所以 在一般情况下都用这种方法引用菜单资源。但是这种方法有一种缺陷:由于是在窗口类中指定的,所有由该窗口类派生出的窗口都有
相同的菜单


第二种方法:
HMENU hMenu
TCHAR MenuName[] = TEXT(“MenuDemo”);
//code
hMenu = LoadMenu(hInstance,MenuName);
hWinMain = CreateWindowEx(WS_EX_CLIENTEDGE,szClassName,szCaptionMain,
WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,hMenu,hInstance,NULL);
通过在CreateWindowsEx第九个参数指定要引入的菜单。CreateWindow调用中的指定菜单可以覆盖窗口类中指定的任何菜单。

第三种方法:
如果我们把CreateWindowEx第九个参数设置为NULL,并且也不在窗口类中指定NULL菜单,就可以在窗口被创建后在给窗口指定指定一个菜单:

SetMenu(hwnd,hMenu);
举个例子 ,在消息处理函数内 static HMENU hMenuFile1,hMenuFile1;
在WM_CREATE:
hInstance = (HINSTANCE)GetWindowsLong(hwnd,GWL_HINSTANCE);
hMenuFile1 = LoadMenu(hInstance,TEXT(“MenuMain1″);    //举个例子
hMenuFile2 = LoadMenu(hInstance,TEXT(“MenuMain2″);面选择资源脚本多次,每个菜单都不同的名字。每当窗口过程处理WM_CREATE消息
的时候windows就会动态的白菜单资源加载到内存中去。SetMenu(hwnd,hMenu)让程序显示hMenu指向的菜单,然后你可以任意
SetMenu(hwnd,hMenuFile1)或者SetMenu(hwnd,hMenuFile2)之间切换,在windows程序设计上面通过按键来实现,这样你甚至可以多创建几个菜单。


下面我们简单地来看看.rc跟菜单资源有关的代码

当我们打开 .rc的资源文件的时候,如果你的工程里面添加了菜单资源的话,那么你可以看到类似下面这样的代码:

OWNMENU MENU                                                                   //OWNMENU是菜单的名称
BEGIN
    POPUP "&File"
    BEGIN
        MENUITEM "&New",                        ID_FILE_NEW
        MENUITEM "&Open",                       ID_FILE_OPEN
        MENUITEM "&Save",                       ID_FILE_SAVE
        MENUITEM "&Exit",                       ID_FILE_EXIT
    END
END
这里的BEGIN 和END跟Pascal程序比较像,如果大家愿意的话其实可以手工用 {  来代替BEGIN   ,用    }  来代替 END。

MENUITEM "&New",                        ID_FILE_NEW   这里的MENUITEM还有另一个选项:POPUP

对于MENUITEM    菜单项会生成一个带有特定ID的WM_COMMAND消息,比如上面这行代码 有ID_FILE_NEW这个ID,当然我们可以在resource.h里面找到它的数字ID

对于POPUP      pop-up,翻译过来以后的意思是突然出现,冒出来的意思,所以在windows编程里我们可以将它理解为"跳出来"的菜单。  该菜单项会激活一个弹出窗口,这时它没有相关联的ID

对于上面的代码,我们应该可以想象在菜单栏有File这个选项,当我们点击File的时候,会弹出New,Open,Save,Exit四个选项,每一个选项当你选中后都会触发WM_COMMAND消息,我们可以把功能写在里面。






你可能感兴趣的:(windowsSDK 菜单资源浅谈)