(转载)Win32 SDK编程系列文章——菜单(快捷菜单)——动态加载

摘要:
WM_ INITMENU消息,wParam:主菜单句柄,lParam:0;当菜单即将激活时,会发送此消息。此消息允许应用程序在显示菜单之前修改菜单。选定项:菜单id或弹出菜单句柄。当用户选择菜单项时,此消息将发送到菜单所属的窗口。WM_ SYSCOMMAND:与WM_ COMMAND消息类似,只有WM_ SYSCOMMAND指示用户从系统菜单中选择启动菜单项,或用户选择最大化、最小化和关闭按钮。Windows预定义的系统菜单项由wParam表示。

理论

创建普通菜单步骤如下:

  • 1)创建菜单 如:CreateMenu
  • 2)   添加菜单项 如:AppendMenu
  • 3)加载菜单         LoadMenu
  • 4)设置菜单到窗口 SetMenu
  • 5)处理菜单响应
  • 6)消除菜单 DestroyMenu

创建右键菜单的步骤如下:

  • 1)创建菜单 如:CreateMenu
  • 2)   添加菜单项 如:AppendMenu
  • 3)使用TrackPopupMenu加载菜单。
  • 4)处理菜单响应
  • 5)消除菜单 DestroyMenu

当然,如果你选择在已有菜单上进行编辑的话,也是可以的,就省略了其中的一些步骤。本节的例子就是在已有的菜单里面添加自己定义的菜单项。对于右键菜单你也可以选择已有的菜单中的一栏作为弹出菜单。 使用菜单后,要涉及清除的问题,和窗口相连的菜单句柄在窗口摧毁的时候会由Windows自动释放,不需要手工释放,但没有和窗口相连的菜单就要由程序自己来释放了,方法是使用DestroyMenu函数,比如没有和窗口相连而仅用TrackPopupMenu弹出的菜单句柄。本例中,我们使用的是窗口关联的菜单句柄,因此我们不需要调用DestroyMenu消除菜单资源。

菜单消息:当用户选择一个菜单项时,windwos通常向窗口过程发送几个不同的消息。在大多数情况下,你的程序可以忽略大部分的消息,只需要把他们传递给DefWindowProc即可。

  1. WM_INITMENU 消息,wParam :主菜单句柄, lParam : 0;这个消息是当一个菜单将要激活时发出。当用户点击菜单栏上的项或者 使用菜单键选择 。这个消息允许应用程序在显示之前修改菜单。可以在这时修改顶层菜单。
  2. WM_MENUSELECT: LOWORD(wParam): 选中项:菜单id或者弹出式菜单句柄。HIWORD(wParam): 选择标; lParam: 包含选中项的菜单句柄。当用户选择某个菜单项时,这个消息就会被发送到菜单所属的窗口。   这个消息是一个菜单跟踪消息,wParam告诉你当前选中的是菜单中的哪一项,wParam的高位字中的“选择标志”可以是下列这些标志的组合: MF_GRAYED、MF_DISABLED、MF_CHECKED、MF_BITMAP、MF_POPUP、MF_HELP、MF_SYSMENU和 MF_MOUSESELECT.   如果你需要根据菜单项的选择来改变窗口客户区的内容,那么可以你可以使用这个消息。
  3. WM_INITMENUPOPUP: wParam:   弹出式菜单句柄;  LOWORD(lParam):弹出式菜单索引;   HIWORD(lParam):系统菜单为1,其他为0 ;   如果要在弹出式菜单显示之前启用或者禁用菜单项,那么这个消息就很重要。
  4. WM_COMMAND: LOWORD(wParam): 菜单id;       HIWOED(wParam): 0 ;     lParam:   0 ;  如果这个消息是由子窗口控制产生,如button产生则:LOWORD(wParam): 控制ID      HIWORD(lParam): 通知码     lParam:     子窗口句柄。如果这个消息是由子窗口或者快捷键产生,则通知码为1,由菜单产生,通知码为0。通过参数,可以区分这个消息的来源是来自于控件,快捷键还是菜单。
  5. WM_SYSCOMMAND: 类似于WM_COMMAND消息,只是WM_SYSCOMMAND表示用户从系统菜单中选择一个启动菜单项或者用户选择最大化,最小化,关闭按钮。 LOWORD(wParam): 菜单id   HIWOED(wParam): 0        lParam:   0;如果消息是由按鼠标产生的,LOWORD(wParam)和HIWORD(lParam)将包含鼠标光标的位置x,y屏幕坐标。对于windows预先定义的系统菜单项,用wParam表示。 SC_CLOSE,SC_MAXIMIZE,SC_MINIMIZE,SC_MOVE等等。

对于已有菜单,我们可以使用GetSystemMenu,GetMenu ,GetSubMenu来获取菜单句柄。当需要更改菜单时,可以使用下面的API进行更改。 AppendMenu, DeleteMenu,InsertMenu,ModifyMenu,RemoveMenu等等。

实例

资源:菜单和快捷键
/////////////////////////////////////////////////////////////////////////////
//
// Menu
IDM_MAIN MENU
BEGIN
    POPUP "文件(&F)"
    BEGIN
        MENUITEM "打开文件(&O)...",                 IDM_OPEN
        MENUITEM "关闭文件(&C)...",                 IDM_OPTION
        MENUITEM SEPARATOR
        MENUITEM "退出(&X)",                      IDM_EXIT
    END
    POPUP "查看(&V)"
    BEGIN
        MENUITEM "字体(&F)...	Alt+F",            IDM_SETFONT
        MENUITEM "背景色(&B)...	Ctrl+Alt+B",      IDM_SETCOLOR
        MENUITEM SEPARATOR
        MENUITEM "被禁用的菜单项",                     IDM_INACT, INACTIVE
        MENUITEM "被灰化的菜单项",                     IDM_GRAY, GRAYED
        MENUITEM SEPARATOR
        MENUITEM "大图标(&G)",                     IDM_BIG
        MENUITEM "小图标(&M)",                     IDM_SMALL
        MENUITEM "列表(&L)",                      IDM_LIST
        MENUITEM "详细资料(&D)",                    IDM_DETAIL
        MENUITEM SEPARATOR
        POPUP "工具栏(&T)"
        BEGIN
            MENUITEM "标准按钮(&S)",                    IDM_TOOLBAR
            MENUITEM "文字标签(&C)",                    IDM_TOOLBARTEXT
            MENUITEM "命令栏(&I)",                     IDM_INPUTBAR
        END
        MENUITEM "状态栏(&U)",                     IDM_STATUSBAR
    END
    POPUP "帮助(&H)"
    BEGIN
        MENUITEM "帮助主题(&H)	F1",                IDM_HELP
        MENUITEM SEPARATOR
        MENUITEM "关于(&A) ...",                  IDM_ABOUT
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
IDC_SDKPOPUPMENU ACCELERATORS
BEGIN
    "/",            IDM_ABOUT,              ASCII,  ALT, NOINVERT
    "?",            IDM_ABOUT,              ASCII,  ALT, NOINVERT
    VK_F1,          IDM_HELP,               VIRTKEY, NOINVERT
    "B",            IDM_SETCOLOR,           VIRTKEY, CONTROL, ALT, NOINVERT
    "F",            IDM_SETFONT,            VIRTKEY, ALT, NOINVERT
END
关键代码
resouces.h
#define IDC_MYICON                      2
#define IDD_SDKPOPUPMENU_DIALOG         102
#define IDS_APP_TITLE                   103
#define IDD_ABOUTBOX                    103
#define IDI_SDKPOPUPMENU                107
#define IDI_SMALL                       108
#define IDC_SDKPOPUPMENU                109
#define IDR_MAINFRAME                   128
#define IDM_MAIN                        0x2000
#define IDA_MAIN                        0x2000
#define IDM_OPEN                        0x4101
#define IDM_OPTION                      0x4102
#define IDM_EXIT                        0x4103
#define IDM_SETFONT                     0x4201
#define IDM_SETCOLOR                    0x4202
#define IDM_INACT                       0x4203
#define IDM_GRAY                        0x4204
#define IDM_BIG                         0x4205
#define IDM_SMALL                       0x4206
#define IDM_LIST                        0x4207
#define IDM_DETAIL                      0x4208
#define IDM_TOOLBAR                     0x4209
#define IDM_TOOLBARTEXT                 0x4210
#define IDM_INPUTBAR                    0x4211
#define IDM_STATUSBAR                   0x4212
#define IDM_HELP                        0x4301
#define IDM_ABOUT                       0x4302 

TCHAR szClassName[] = L"Menu Example";
TCHAR szCaptionMain[] = L"menu";
TCHAR szMenuHelp[] = L"帮助主题(&H)";  
TCHAR szMenuAbout[] = L"关于本程序(&A)..."; 
HWND g_hWinMain;
HMENU g_hMenu;
HMENU g_hSubMenu;
void DisplayMenuItem(DWORD dwCommandID)
{
    TCHAR szBuffer[256] = {0};
    wsprintf(szBuffer, L"您选择了菜单命令:%08x",dwCommandID);
    MessageBox(g_hWinMain,szBuffer, L"菜单选择",MB_OK);
}  
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 将实例句柄存储在全局变量中 
   g_hMenu = LoadMenu(hInstance,MAKEINTRESOURCE(IDM_MAIN));//加载菜单资源,返回菜单句柄
   g_hSubMenu = GetSubMenu(g_hMenu,1); //获取主菜单的第2个子菜单,用作快捷菜单
   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, g_hMenu, hInstance, NULL);//把菜单放到窗口中
   g_hWinMain=hWnd;
   if (!hWnd)
   {
      return FALSE;
   }
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   return TRUE;
} 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    POINT stPos;
    HMENU hSysMenu;
    switch (message)
    {
    case WM_CREATE:
        hSysMenu = GetSystemMenu(hWnd,FALSE);//获取系统菜单句柄
        AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL);//把分割线附加到系统菜单中
        AppendMenu(hSysMenu,0,IDM_HELP,szMenuHelp);//把菜单项help附加到系统菜单中
        AppendMenu(hSysMenu,0,IDM_ABOUT,szMenuAbout);//把菜单项about附加到系统菜单中
        break;
    case WM_COMMAND: //用户菜单项命令的消息
        DisplayMenuItem(wParam);//显示对话框
        //对于单项项的标识(单项,双选)的标识
        if(LOWORD(wParam) == IDM_EXIT)
        {
            DestroyWindow(hWnd); 
        } 
        else if(LOWORD(wParam) >= IDM_TOOLBAR &&    LOWORD(wParam) <= IDM_STATUSBAR) //多选的  工具栏的:标准按钮,命令栏,文字标签   
        {
            UINT uState = GetMenuState(g_hMenu,LOWORD(wParam),MF_BYCOMMAND);
            if(uState == MF_CHECKED)
                uState = MF_UNCHECKED;
            else
                uState = MF_CHECKED;
            CheckMenuItem(g_hMenu,LOWORD(wParam),uState);//复选或撤销指定菜单的菜单条目
        }
        else if(LOWORD(wParam) >= IDM_BIG && LOWORD(wParam) <= IDM_DETAIL)//单选的  大图标,小图标,列表,详细资料
        {
            CheckMenuRadioItem(g_hMenu,IDM_BIG,IDM_DETAIL,LOWORD(wParam),MF_BYCOMMAND);//单选[IDM_BIG,IDM_DETAIL]中的一个
        }
        //CheckMenuItem,CheckMenuRadioItem分别用于改变菜单项的状态。菜单项的状态可以通过GetMenuState函数获得。
        break;
    case WM_SYSCOMMAND://系统菜单项的命令消息
        if(LOWORD(wParam) == IDM_HELP || LOWORD(wParam) == IDM_ABOUT)//附加到系统菜单的help,about的菜单项
            DisplayMenuItem(wParam);
        else
            return DefWindowProc(hWnd,message,wParam,lParam);
        break;
    case WM_RBUTTONDOWN:
        GetCursorPos(&stPos);//获取光标位置
        TrackPopupMenu(g_hSubMenu,TPM_LEFTALIGN,stPos.x,stPos.y,NULL,hWnd,NULL);//在指定位置显示快捷菜单,并跟踪菜单选项
        break; 
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps); 
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

免责声明:文章转载自《(转载)Win32 SDK编程系列文章——菜单(快捷菜单)——动态加载》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇keil将程序装入外部FLASH具体解释MySQL导入、导出、数据库定时备份下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C# 获取显示器的物理尺寸或分辨率

还是那个项目……还是那个领导……要求获取用户的显示器尺寸。一脸懵逼???还是照做…… 获取显示器的尺寸,有两种方法。第一种是通过查询注册表中,存储的指定显示器的相关信息;第二种是通过windows API 1、查询注册表中存储的显示器信息 /// <summary> ///获取显示器的相关硬件ID /// </summary> //...

5、Windows API,进程和线程、控件与消息

11. API之进程和线程函数 CancelWaitableTimer 这个函数用于取消一个可以等待下去的计时器操作 CallNamedPipe 这个函数由一个希望通过管道通信的一个客户进程调用 ConnectNamedPipe 指示一台服务器等待下去,直至客户机同一个命名管道连接 CreateEvent 创建一个事件对象 CreateMailslot 创...

lua文件读写

lua里的文件读写模型来自C语言,分为完整模型(和C一样)、简单模型。 1、简单模型 io.input([file]) 设置默认的输入文件,file为文件名(此时会以文本读入)或文件句柄(可以理解为把柄,有了把柄就可以找到文件),返回文件句柄。 io.output([file])设置默认的输出文件,参数意义同上。 io.close([file])关闭文件,...

Windows API 教程(七) hook 钩子监听

茵蒂克丝 如何创建一个窗口 手动创建窗口的流程 实际代码 安装钩子 (Install hook) 钩子简介 SetWindowsHookEx 函数 设置监听【键盘】消息 设置监听【鼠标】消息 如何创建一个窗口 另外一个再录的 Windows SDK教程 里面有讲到快捷创建窗口的方式,不过这样的话要分好几个文件,感觉有点混所以这里就用原始的...

delphi之多线程编程(一)

本文的内容取自网络,并重新加以整理,在此留存仅仅是方便自己学习和查阅。所有代码均亲自测试 delphi7下测试有效。图片均为自己制作。 多线程应该是编程工作者的基础技能, 但这个基础我从来没学过,所以仅仅是看上去会一些,明白了2+2的时候,其实我还不知道1+1。 开始本应该是一篇洋洋洒洒的文字, 不过我还是提倡先做起来, 在尝试中去理解. 先试试这个:...

得到控制台窗口的句柄

得到控制台窗口的句柄 调用 GetConsoleTitle() 来保存当前的控制台窗口标题。 调用 SetConsoleTitle() 来将控制台标题更改为一个唯一的标题。 调用 Sleep(40),以确保已更新窗口标题。 调用 FindWindow(NULL, uniquetitle),以获取 HWND,此调用将返回 HWND, 如果操作失败,将返回...