卓航论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 210|回复: 3
打印 上一主题 下一主题

Win32开发入门(4) 创建菜单

[复制链接]
[至尊红钻5级]发帖数量≥8000篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [至尊紫钻4级]金币≥20000个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 论坛元老
 UID:  7   [未点亮普号显示]钻石不足3个
 阁 分: 36567
 阁 望: 0
 阁 献: 0
 活 跃: 0
 发 贴: 12405 (0)
 阁 币: 24162  
性 别: I'm 火星人!
阅读权限: 90
在线时长: 0 小时
注册时间: 2016-10-16
最后登录: 2016-10-18
go
楼主
发表于 2016-10-17 16:23:06 |只看该作者 |倒序浏览
本帖发表于 2016-10-17 16:23:06...阅读 211 人...加油,亲爱的楼主:[db:作者]
我们当然知道 ,现在,在实际开发中肯定不会像我这样写Win32程序的,你看,连个WinMain都要N行代码。但很多人 不明白什么叫学习,什么叫探索。实际上,通常能用于实际开发中的技巧只是占我们对客观世界的认识 总和不到20%,所以,如果你有兴趣计算一下,估计有80%的知识你不知道用到哪里去了。就算我们今后 不会把Win32程序投入到实际操作中,然而如果你了解过这东西,你会发现很多时候对我们是有帮助的 。
哪怕只是简单认识一下Win32的一些原理,相信对于日后编程的学习和成长,是有益处的。
为了提高误人子弟的效果,上面我说了几段F话,下面开始今天的正题。
要在窗口上添 加菜单,当然你可能会研究出N种方法,不过,这里我说两种,一种相当复杂,另一种稍微简单。
方法一,用代码添加菜单
这种方法的思路是:首先在全局范围内定义一个HMENU的变量 ,用来保存窗口中菜单栏的句柄,根菜单(菜单栏)可以CreateMenu函数来创建,接着可以使用 AppendMenu函数或者InsertMenuItem函数来创建菜单项。
句柄就是内存中各种资源的ID,比如 图标,图片,字符串等。我们的菜单也是一种资源。
下面我写了一个函数,用来动态创建菜单 。
void CreateMyMenu()     
{     
    hRoot = CreateMenu();     
    if(!hRoot)     
        return;     
    HMENU pop1 = CreatePopupMenu();     
    AppendMenu(hRoot,     
        MF_POPUP,     
        (UINT_PTR)pop1,     
        L"操作");     
    // 一种方法是使用AppendMenu函数     
    AppendMenu(pop1,     
        MF_STRING,     
        IDM_OPT1,     
        L"飞机");     
         
    // 另一种方法是使用InsertMenuItem函数     
    MENUITEMINFO mif;     
    mif.cbSize = sizeof(MENUITEMINFO);     
    mif.cch = 100;     
    mif.dwItemData  = NULL;     
    mif.dwTypeData = L"机关枪";     
    mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;     
    mif.fState = MFS_ENABLED;     
    mif.fType = MIIM_STRING;     
    mif.wID = IDM_OPT2;     
         
    InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);     
         
}
               
hRoot是在外部定义的全局变量,保存菜单栏的标识。完整的代码如下:
#include
     
         
#define IDM_OPT1     301     
#define IDM_OPT2     302     
         
HMENU hRoot;     
void CreateMyMenu();//创建菜单     
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);     
         
         
int CALLBACK WinMain(HINSTANCE hInstance,     
                    HINSTANCE hPrevInstance,     
                    LPSTR cmdLine,     
                    int nShow)     
{     
    CreateMyMenu();//创建菜单     
    WCHAR* cn = L"Myapp";     
    WNDCLASS wc={   };     
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;     
    wc.lpszClassName = cn;     
    wc.style = CS_HREDRAW | CS_VREDRAW;     
    wc.hInstance = hInstance;     
    wc.lpfnWndProc = (WNDPROC)MyWinProce;     
    RegisterClass(&wc);     
    HWND hm = CreateWindow(cn,     
        L"我的应用程序",     
        WS_OVERLAPPEDWINDOW,     
        20,     
        15,     
        420,     
        360,     
        NULL,     
        hRoot,     
        hInstance,     
        NULL);     
    if( hm == NULL )     
        return 0;     
    ShowWindow(hm,nShow);     
    MSG msg;     
    while(GetMessage(&msg,NULL,0,0))     
    {     
        TranslateMessage(&msg);     
        DispatchMessage(&msg);     
    }     
         
    return 0;     
}     
         
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    switch(msg)     
    {     
    case WM_DESTROY:     
        //DestroyMenu(hRoot);     
        PostQuitMessage(0);     
        return 0;     
    default:     
        return DefWindowProc(hwnd, msg, wParam,lParam);     
    }     
}     
         
void CreateMyMenu()     
{     
    hRoot = CreateMenu();     
    if(!hRoot)     
        return;     
    HMENU pop1 = CreatePopupMenu();     
    AppendMenu(hRoot,     
        MF_POPUP,     
        (UINT_PTR)pop1,     
        L"操作");     
    // 一种方法是使用AppendMenu函数     
    AppendMenu(pop1,     
        MF_STRING,     
        IDM_OPT1,     
        L"飞机");     
         
    // 另一种方法是使用InsertMenuItem函数     
    MENUITEMINFO mif;     
    mif.cbSize = sizeof(MENUITEMINFO);     
    mif.cch = 100;     
    mif.dwItemData  = NULL;     
    mif.dwTypeData = L"机关枪";     
    mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;     
    mif.fState = MFS_ENABLED;     
    mif.fType = MIIM_STRING;     
    mif.wID = IDM_OPT2;     
         
    InsertMenuItem(pop1,IDM_OPT2,FALSE,&mif);     
         
}

               
方法二,通过编辑资源来添加菜单
上面的方法虽然创建了菜单,但你 也看到了,是相当地不方便,所以,下面我重点介绍一下用资源编辑器来创建菜单资源。
在你 的开发工具上,依次找到菜单项【视图】【资源视图】。

在资源视图中,右击项目根节点,从弹出的菜单中选择【添加】【资源】。

在随后弹出的对话框中,选择Menu,单击右边的“新建”按钮。

可以通过属性窗口来重命名菜单的ID。

               
我们可以使用可视化视图来建立菜单,为了可以在代码中使用,给需要的菜单一个ID,这个 名字你可以自己喜欢,只是惯用的是以IDM_开头,意思是Menu ID,比如IDC开头的,意思是Control ID 等等。

编辑好之后,保存,在【解决方案资源管理器】中你会看到一个resource.h 文件,其实我们为资源定义的ID都以宏的形式声明的,不信你打开看看。

资源ID都是数字,只是为它定义个名字,方便识别罢了,就好像人们平时只叫你的名字或者 小名,你见过谁会叫你的身份证号码的?
开发工具生成的ID有时候会有问题,或者有些ID我们 在程序中没用上,如果你觉得它们留在代码文件中会影响市容的话,你可以这样:
1、在【资源 视图】窗口中,右击,从弹出的快捷菜单中选择【资源符号...】,弹出一个窗口,这里可以看到应用 程序中的资源ID列表,以及哪些ID已被使用,但是,这个窗口中显示的内容,有时候不准确,有些ID明 明没有被使用,它右边却打上了勾。
这里可以修改ID的值,也可以新建资源ID,所以,你也可 以在这里预先为资源分配ID,然后在属性窗口设置资源的标识时,从下拉列表中选择指定的ID。资源ID 的名字和数值不能重复,但是,不同的资源是可以使用同一个资源ID的。例如,通常在应用程序中,某 些菜单项的功能和工具栏上的按钮是一一对应的,功能相同,这种情况下,我们可以考虑让它们共用一 个ID。
2、你可以直接打开resource.h头文件,直接在上面修改。
响应菜单命令
当用户单击某个菜单项后,窗口处理程序(WindowProc)会收到一条WM_COMMAND消息,它的两个附加参 数如下:

               
在收到WM_COMMAND后,我们可以用LOWORD取得它的低数位, 上表中已经说明,wParam的低位值表示菜单的资源ID,我们通过它的值与哪个菜单的ID相等,就知道用 户点击了哪个菜单项。
所以,我们的程序代码现在应为:
#include
     
#include "resource.h"     
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);     
         
         
int CALLBACK WinMain(HINSTANCE hInstance,     
                    HINSTANCE hPrevInstance,     
                    LPSTR cmdLine,     
                    int nShow)     
{     
    WCHAR* cn = L"Myapp";     
    WNDCLASS wc={   };     
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;     
    wc.lpszClassName = cn;     
    wc.style = CS_HREDRAW | CS_VREDRAW;     
    wc.hInstance = hInstance;     
    wc.lpfnWndProc = (WNDPROC)MyWinProce;     
    RegisterClass(&wc);     
    HWND hm = CreateWindow(cn,     
        L"我的应用程序",     
        WS_OVERLAPPEDWINDOW,     
        20,     
        15,     
        420,     
        360,     
        NULL,     
        // 加载菜单资源     
        LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAIN)),     
        hInstance,     
        NULL);     
    if( hm == NULL )     
        return 0;     
    ShowWindow(hm,nShow);     
    MSG msg;     
    while(GetMessage(&msg,NULL,0,0))     
    {     
        TranslateMessage(&msg);     
        DispatchMessage(&msg);     
    }     
         
    return 0;     
}     
         
         
LRESULT CALLBACK MyWinProce(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)     
{     
    switch(msg)     
    {     
    case WM_COMMAND:     
        {     
            // 取出资源Id值     
            // 并判断用户选择了哪个菜单项     
            switch(LOWORD(wParam))     
            {     
            case IDM_PLANE:     
                MessageBox(hwnd,L"灰机来了。",L"提示",MB_OK);     
                break;     
            case IDM_GUN:     
                MessageBox(hwnd,L"让炮弹飞。",L"提示",MB_OK);     
                break;     
            case IDM_MT_GUN:     
                MessageBox(hwnd,L"山炮欲来风满楼。",L"提示",MB_OK);     
                break;     
            default:     
                break;     
            }     
        }     
        return 0;     
    case WM_DESTROY:     
        PostQuitMessage(0);     
        return 0;     
    default:     
        return DefWindowProc(hwnd, msg, wParam,lParam);     
    }     
}
               
在注册窗口类时,如要设置菜单,调用LoadMenu函数,第一个参数是当前程序实例的句柄, 从WinMain的参数中获得,第二个参数是菜单的ID,因为这里要名字,字符串,而我们的ID都是数值, 可通过MAKEINTRESOURCE宏转换。至于MessageBox函数就不用我介绍了。

好了,我们的应用程序已经创建了菜单了。
呵,有人说我的编程学习方法很奇特,其 实,我们何苦要墨守成规呢,局限在定势思维中呢?枯躁无味的东西,你可以人为地让它变得充满乐趣 ,关键是你的心态罢了。这让我想起,以前某同学A跟我讨论两个问题:
1、我的程序只想保存 用户的一些使用设置,用数据库没必要,写注册不环保;
2、我有一个dll类库,我希望最后我 的程序既可以引用它,但同时只生成一个exe文件,能做到吧。
我就说了,问题一好办,你定义 一个存放设置项的类,把它直接进行XML序列化和反序列化就完事了,这既能保存数据,又可以封装对 象。如果不想让别人看到XML文件中的内容,就把它用DES算法加密/解密;而第二个问题,你把dll文件 当成资源嵌入到程序的资源文件中,运行时如果要用到类库的类,那就把它反射出来,动态调用就行了 。
然后他说,这好像没有人这样做,老师也没教过。
我说:靠,你老爸小时候教过你泡 妞吗?你一上大学怎么就学会了泡妞?四年大学还换了N个妞,我一个都没换成,你的爱情事业如此成 功。再说了,吕不韦临死前有教过秦始皇怎么统一中华吗?难道秦始皇会说:以前没人统一过华夏,我 怎么统一?最后他老人家还是把六国给干掉了。
分享到: QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏0 支持支持0 反对反对0

使用道具 举报

[至尊红钻3级]发帖数量≥1000篇 [至尊黄钻3级]威望≥500点 [至尊蓝钻1级]在线时间≥10小时 [至尊绿钻9级]贡献度≥80000点 [至尊紫钻9级]金币≥8000000个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 管理员
 UID:  1   [未点亮普号显示]钻石不足3个
 阁 分: 2147483647
 阁 望: 993
 阁 献: 2147483647
 活 跃: 0
 发 贴: 1532 (0)
 阁 币: 9430326  
性 别: I'm 火星人!
阅读权限: 200
在线时长: 46 小时
注册时间: 2016-10-14
最后登录: 2023-10-3
沙发
发表于 2016-10-18 00:04:14 |只看该作者
本回复帖发表于 2016-10-18 00:04:14,感谢爱情孤儿对本帖的认真回复,你的回复是对楼主莫大的鼓舞
学习了,谢谢分享、、、

使用道具 举报

[至尊红钻2级]发帖数量≥100篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 注册会员
 UID:  67   [未点亮普号显示]钻石不足3个
 阁 分: 158
 阁 望: 2
 阁 献: 9
 活 跃: 0
 发 贴: 140 (0)
 阁 币: 5  
性 别: I'm 火星人!
阅读权限: 20
在线时长: 5 小时
注册时间: 2011-1-6
最后登录: 2016-10-21
板凳
发表于 2016-10-19 13:40:14 |只看该作者
本回复帖发表于 2016-10-19 13:40:14,感谢luckyboy123对本帖的认真回复,你的回复是对楼主莫大的鼓舞
看帖回帖是美德!

使用道具 举报

[至尊红钻2级]发帖数量≥100篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 中级会员
 UID:  51   [未点亮普号显示]钻石不足3个
 阁 分: 205
 阁 望: 5
 阁 献: 3
 活 跃: 0
 发 贴: 182 (0)
 阁 币: 10  
性 别: I'm 火星人!
阅读权限: 30
在线时长: 5 小时
注册时间: 2011-1-6
最后登录: 2016-10-21
地板
发表于 2016-10-21 08:46:08 |只看该作者
本回复帖发表于 2016-10-21 08:46:08,感谢wangxuejing1109对本帖的认真回复,你的回复是对楼主莫大的鼓舞
没看完~~~~~~ 先顶,好同志

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1、请认真发帖,禁止回复纯表情,纯数字等无意义的内容!帖子内容不要太简单!
2、提倡文明上网,净化网络环境!抵制低俗不良违法有害信息。
3、每个贴内连续回复请勿多余3贴,每个版面回复请勿多余10贴!
4、如果你对主帖作者的帖子不屑一顾的话,请勿回帖。谢谢合作!

手机版| 百度搜索:vkee.pw

2012-2015 卓航旗下 GMT+8, 2024-6-18 02:17 , Processed in 6.050654 second(s), 30 queries . Powered by Discuz! X3.2  

禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.如遇版权问题,请及时联系站长(QQ:5213513)

今天是: | 本站已经安全运行: //这个地方可以改颜色

快速回复 返回顶部 返回列表