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) ; }
写完以后我新建一个资源文件,然后在里面添加菜单资源。

接下来我编辑菜单如下图所示:

注意一下系统默认的菜单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消息,我们可以把功能写在里面。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值