Win32编程API 基础篇 -- 6.菜单和图标

菜单和按钮

例子:菜单1

  本小节仅仅向你展示如果向你的窗口中加入一个基本的菜单,通常你会用到一个提前制作好的菜单资源,这会是一份.rc文件并且会被编译链接进你的.exe可执行程序中。这是具体的流程做法,而商业编译器将会有一个资源编辑器,你可以通过这个编辑器来创建菜单,但是在这个例子中我会向你展示如何用.rc文件的手动写法。通常我会配合使用一个头文件,在资源文件和源文件中我们需要引入这个头文件,这个头文件中包含了控制和菜单选项等的标识符。

  在本小节的栗子中,你可以按照指示在simple_window代码的基础上做改造。

  首先头文件名通常会叫“resource.h”

1 #define IDR_MYMENU 101
2 #define IDI_MYICON 201
3
4 #define ID_FILE_EXIT 9001
5 #define ID_STUFF_GO 9002

  没有更多的东西,我们的菜单很简单,标识符名和ID号由你自己选择,现在我们来写.rc文件的代码。

 1 #include "resource.h"
 2
 3 IDR_MYMENU MENU
 4 BEGIN
 5     POPUP "&File"
 6     BEGIN
 7         MENUITEM "E&xit", ID_FILE_EXIT
 8     END
 9
10     POPUP "&Stuff"
11     BEGIN
12         MENUITEM "&Go", ID_STUFF_GO
13         MENUITEM "G&o somewhere else", 0, GRAYED
14     END
15 END
16
17 IDI_MYICON ICON "menu_one.ico"

  根据你使用的工具,将.rc文件加入你的项目或生成文件中。

  你也要在你的源文件中使用#include “resource.h”引入资源头文件。

  在你的窗口中附加菜单和图标最简单的方式就是在注册窗口类是指定好,就像下面:

1     wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MYMENU);
2
3     wc.hIcon  = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON));
4     wc.hIconSm  = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MYICON), IMAGE_ICON, 16, 16, 0);

  在原来的代码上面改看看会发生什么,你的窗口现在应该有一个File和Stuff的菜单,这种是你的资源文件被成功编译并链接至程序中的情况,如果发生错误请检查。

  窗口右上角的图标和任务栏上的指定的小图标现在应该能够显示出来了,如果你使用Alt-Tab的组合键你会看到应用列表的大图标。

  我曾经用loadIcon()来加载小图标因为它更简单,但是这个方法加载的图标的默认大小是32x32,为了加载小图标我们需要使用LoadImage()方法。请注意图标文件和资源可以包含多个图像,在这种情况下我提供了加载资源图标的两个尺寸。

例子:菜单2

  另一种使用菜单资源的选择是动态创建(即你的程序运行的时候),这是一种更加聪明的工作方式,有时为了增加程序的灵活性是有必要的。

  你也可以使用没有存储在资源中的图标,而选择在运行的时候单独加载存储图标的文件,这也给了你一种选择,即允许用户在通用的对话框中选择图标,在后面我们会讨论到,或者其他受动态创建影响的东西。

  让我们再一次从没有资源文件和头文件的simple_windows的代码开始,现在我们将会处理WM_CREATE消息然后向我们的窗口中增加菜单。

1 #define ID_FILE_EXIT 9001
2 #define ID_STUFF_GO 9002

  现在把这两个id放在你的源文件的头部,就在#include的下面,现在我们把下面的代码加入到WM_CREATE消息的句柄中:

 1 case WM_CREATE:
 2     {
 3         HMENU hMenu, hSubMenu;
 4         HICON hIcon, hIconSm;
 5
 6         hMenu = CreateMenu();
 7
 8         hSubMenu = CreatePopupMenu();
 9         AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
10         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");
11
12         hSubMenu = CreatePopupMenu();
13         AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
14         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");
15
16         SetMenu(hwnd, hMenu);
17
18
19         hIcon = LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
20         if(hIcon)
21             SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
22         else
23             MessageBox(hwnd, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR);
24
25         hIconSm = LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
26         if(hIconSm)
27             SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
28         else
29             MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);
30     }
31     break;

  这个跟第一个例子的效果一样,创建了一个菜单附加到我们的窗口中,当程序终止时,指定附加到窗口的菜单会自动被移除。所以我们不要担心如何除掉它,如果我们想这样做,可以使用GetMenu()和DestroyMenu()来达到目的。

  加载图标的代码相当简单,这里我们调用了两次LoadImage(),分别加载16x16和32x32尺寸的图标,我们不能使用LoadIcon()因为它只能加载资源文件,而不是图标文件本身。我们为实例句柄参数指定了一个NULL的参数因为我们不是从一个模块中加载资源的,我们通过传递我们想要加载的图标文件名而不是资源ID。最后我们通过LR_LOADFROMFILE标识表明我们想要函数我们传递进入的字符串当做文件名而不是一个资源名。

  如果图标加载成功,我们会将图标通过WM_SETICON分配给窗口;如果失败了,会弹出一个告诉我们加载出错的对话框。

  注意:如果突变文件不在我们程序的当前工作目录下那么调用LoadImage()会失败。如果你使用VC++并且从IDE运行程序,当前工作目录会是项目文件所在的目录中的一个。如果你使用浏览器的调试或发布目录或者命令行运行程序,那么你需要将图标文件复制进相应的工作目录中以便程序可以找到它;如果都不行,尝试用绝对路径"C:\\Path\\To\\Icon.ico"

  OK,现在我们有自己的菜单了,我们需要让它做些东西,这相当简单,我们需要做的就是处理WM_COMMAND消息。同样我们需要检查得到了哪些命令然后根据它做处理,现在我们的WndProc()看起来影响像下面这样了。

 1 LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
 2 {
 3     switch(Message)
 4     {
 5         case WM_CREATE:
 6         {
 7             HMENU hMenu, hSubMenu;
 8
 9             hMenu = CreateMenu();
10
11             hSubMenu = CreatePopupMenu();
12             AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
13             AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");
14
15             hSubMenu = CreatePopupMenu();
16             AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
17             AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");
18
19             SetMenu(hwnd, hMenu);
20
21
22             hIcon = LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
23             if(hIcon)
24                 SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
25             else
26                 MessageBox(hwnd, "Could not load large icon!", "Error", MB_OK | MB_ICONERROR);
27
28             hIconSm = LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
29             if(hIconSm)
30                 SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
31             else
32                 MessageBox(hwnd, "Could not load small icon!", "Error", MB_OK | MB_ICONERROR);
33         }
34         break;
35         case WM_COMMAND:
36             switch(LOWORD(wParam))
37             {
38                 case ID_FILE_EXIT:
39
40                 break;
41                 case ID_STUFF_GO:
42
43                 break;
44             }
45         break;
46         case WM_CLOSE:
47             DestroyWindow(hwnd);
48         break;
49         case WM_DESTROY:
50             PostQuitMessage(0);
51         break;
52         default:
53             return DefWindowProc(hwnd, Message, wParam, lParam);
54     }
55     return 0;
56 }

  正如你看到了我们得到了所有设置的WM_COMMAND,甚至它有自己的switch,这个switch的值是根据wParam的低字来判断的,wParam对于WM_COMMAND来说包含了发送消息的控制或菜单id。

  很明显,我们想要退出菜单选项实现关闭程序的功能,所以在WM_COMMAND的ID_FILE_EXIT句柄下你可以使用以下的代码来达到目的。

1 PostMessage(hwnd, WM_CLOSE, 0, 0);

  你的WM_COMMAND消息处理程序看起来应该像下面这样子:

 1     case WM_COMMAND:
 2         switch(LOWORD(wParam))
 3         {
 4             case ID_FILE_EXIT:
 5                 PostMessage(hwnd, WM_CLOSE, 0, 0);
 6             break;
 7             case ID_STUFF_GO:
 8
 9             break;
10         }
11   break;

  我留给你实现另一个ID_STUFF_GO菜单命令做点什么。

程序文件图标

  你可能注意到了menu_one.exe文件现在像我们用资源文件引入图标的方式显示了图标,然而menu_two.exe并没有这样做因为我们引入了一个外部文件。窗口浏览器在第一个程序中通过资源文件非常简单的显示了一个图标,因为只需要一个图标;如果我们想通过程序显示一个确切地图标,那么就可以采取第一种方式,即简单地使用资源ID;如果你想要根据你的选择显示图标那么就采取第二种方式吧。

  PS.由于本人英文水平所限,只能翻译到这个程度了,有纰漏还望多多指出,附上本篇翻译的英文原版教程地址:http://www.winprog.org/tutorial/menus.html

时间: 2024-09-30 16:44:10

Win32编程API 基础篇 -- 6.菜单和图标的相关文章

Win32编程API 基础篇 -- 1.入门指南 根据英文教程翻译

入门指南 本教程是关于什么的 本教程的目的是向你介绍使用win32 API编写程序的基础知识(和通用的写法).使用的语言是C,但大多数C++编译器也能成功编译,事实上,教程中的绝大多数内容都适用于任何可以连接API的语言,包括Java.Assembly和Visual Basic:我不会向你呈现任何跟这些语言相关的代码,这需要你在本教程的指导下自己去完成,有一些人在本API的基础上使用其他语言进行编程取得了相当的成功. 本教程不会教你C语言,也不会告诉你怎样去运行你特定的编译器(Borland C

Win32编程API 基础篇 -- 4.消息循环 根据英文教程翻译

理解消息循环 为了编写任何即使是最简单的程序,了解windows程序的消息循环和整个消息发送结构是非常有必要的.既然我们已经尝试了一点消息处理的东西,我们应该对整个程序有更深入的理解,如果你没有理解消息是怎么发生的和它们运行的机制,那接下来的内容你会感到很蛋疼. 什么是消息? 一条消息是一个整数值,如果你查阅你的头文件(这是个好的查阅API的工作惯例)你会发现像下面的东西: 1 #define WM_INITDIALOG 0x0110 2 #define WM_COMMAND 0x0111 3

Win32编程API 基础篇 -- 5.使用资源

使用资源 你可能想参考教程结尾的附近,为了获得跟VC++和BC++资源相关的信息. 在我们讲得更加深入之前,我将大致讲解一下资源的主题,这样在每个小节中我就不必再去重讲一遍了.在这一小节中,你不需要编译任何东西,这里的代码只是个例子. 资源是以二进制的格式存储在你的可执行文件内部的预定义的数据,在资源脚本中我们创建资源,所谓的资源脚本就是有”.rc”扩展名的群文件,商业编译器通常有一个视觉资源编辑器老让你在不需要手动编辑的情况下创建资源,但很多时候手动这是唯一的创建资源的方法,如果你的编译器没有

Win32编程API 基础篇 -- 3.消息处理 根据英文教程翻译

消息处理 例子:窗口点击 好的,现在我们已经得到一个窗口了,但我们什么也做不了除了DefWindowProc()允许窗口大小被调整,最大最小化等...这不是很激动人心啊 在接下来的一小节中我将向你展示如何修改现有的程序,让它做一些新的事情,这样我就可以告诉你,“处理消息然后这样做...”,我会明白我的意思是什么并且在不需要看完完整的栗子的基础上完成它.所以不管怎样,集中注意力 OK,对初学者来说拿最近的一个窗口程序的代码,保证编译通过并且正常运行,然后你就可以在这份代码的基础上进行一些小修改,或

Win32编程API 基础篇 -- 2.一个简单的窗口 根据英文教程翻译

一个简单的窗口 例子:简单的窗口 有时人们在IRC提问,”我应该怎样制作一个窗口”...嗯,这恐怕不是完全这么简单好回答!其实这并不难一旦你明白你在做什么,但在你得到一个可展示的窗口之前还有一些事情需要我们去做,我们只需要简单地聊聊快速做下笔记,这个问题就能被很简单的回答. 我很喜欢先动手再学习...一下就是一个简单的窗口的程序,我们将会简短的对它进行解释说明. 1 #include <windows.h> 2 3 const char g_szClassName[] = "myWi

shell脚本编程之基础篇(二)

shell脚本编程之基础篇(二) ============================================================================== 概述: ============================================================================== 退出状态 ★进程使用退出状态来报告成功或失败 ◆0 代表成功,1-255代表失败 ◆$? 变量保存最近的命令退出状态 (查看:echo $?)

cocos2dx基础篇(7)——菜单按钮CCMenu、CCMenuItem

[本节内容] 菜单按钮在游戏中是经常被用到的,比如主菜单界面的菜单选项,暂停游戏时的菜单选项等等.cocos2dx引擎同样为我们提供了CCMenu菜单的功能,并包含了一些简单的菜单项CCMenuItem.且菜单项附带触碰按钮时,自动放大的效果. 温馨提示:本节内容比较多,需要大家慢慢分析,不要急于求成. 本节组织结构如下: 一.介绍CCMenu. 二.介绍CCMenuItem,及其具体的六个子类. 三.代码实战. [一.菜单CCMenu] 菜单CCMenu是专门用来承载菜单按钮的CCLayer图

(转)Android高性能编程(1)--基础篇

关于专题     本专题将深入研究Android的高性能编程方面,其中涉及到的内容会有Android内存优化,算法优化,Android的界面优化,Android指令级优化,以及Android应用内存占用分析,还有一些其他有关高性能编程的知识.    随着技术的发展,智能手机硬件配置越来越高,可是它和现在的 PC 相比,其运算能力,续航能力,存储空间等都还是受到很大的限制,同时用户对手机的体验要求远远高于 PC 的桌面应用程序.以上理由,足以需要开发人员更加专心去实现和优化你的代码了.选择合适的算

Java socket编程API基础

Socket是Java网络编程的基础,深入学习socket对于了解tcp/ip网络通信协议很有帮助, 此文讲解Socket的基础编程.Socket用在哪里:①.主要用在进程间,②.网络间通信. 文章目录如下: 一.Socket通信基本示例 二.消息通信优化 2.1 双向通信,发送消息并接受消息 2.2 使用场景 2.3 如何告知对方已发送完命令 2.3.1 通过Socket关闭 2.3.2 通过Socket关闭输出流的方式 2.3.3 通过约定符号 2.3.4 通过指定长度 三.服务端优化 3.