11.菜单(一)

1.菜单的分类

  菜单其实是一个容器,容器中放的每个菜单项。

  HMENU类型表示菜单,菜单每一项有相应的ID。

  (1)窗口顶层菜单

     窗口标题栏和客户区之间的区域。

  (2)弹出式菜单

     例如:右键菜单、下拉菜单等

  (3)系统菜单

2.菜单的使用

  (1)窗口顶层菜单

      创建菜单:HMENU CreateMenu(VOID);  //成功返回菜单句柄

      添加菜单项:BOOL AppendMenu( HMENU       hMenu,          //菜单句柄

                                                            UINT          uFlag,            //菜单顶风格

                                                            UINT_PTR   uIDNewItem,  //菜单ID或下拉菜单句柄

                                                            LPCTSTR     lpNewItem);   //菜单项名称

      菜单风格:MF_POPUP - 具有这种风格的菜单项,被点击后弹出下拉菜单或子菜单,uIDNewItem必须设置下拉菜单或子菜单句柄。

             MF_SEPARATOR - 具有这种风格的菜单项,为分割线。

             MF_STRING  - 具有这个风格的菜单项,被点击后能发出消息(WM_COMMAND)。

      设置到窗口:BOOL SetMenu( HWND   hWnd,    //窗口句柄

                                                      HMENU  hMenu);  //菜单句柄

  (2)弹出式菜单

      创建菜单:HMENU CreatePopupMenu(VOID);  //成功返回菜单句柄

      加入顶层菜单:BOOL AppendMenu( HMENU      hMenu,           //菜单句柄

                                                               UINT         uFlag,             //菜单顶风格

                                                               UINT_PTR  uIDNewItem,   //菜单ID或下拉菜单句柄

                                                               LPCTSTR    lpNewItem);   //菜单项名称

  (3)菜单命令处理

       WM_COMMAND消息

     wPARAM:HIWORD - 对于菜单为0

                              LOWORD - 菜单项ID

     lPARAM:对于菜单为NULL

     命令处理过程:获取(WPARAM的LOWORD)菜单ID,根据ID处理

  (4)菜单项的状态

      在增加菜单项可以设置菜单项的状态,可以使用菜单API(CheckMenuItem、EnableMenuItem)修改状态。

     //设置菜单项勾选/非勾选状态

     DWOED CheckMenuItem( HMENU  hMenu,            //菜单句柄

                                                   UINT     uIDCheckItem,  //菜单项ID或位置(索引)

                                                   UINT     uCheck);          //具体状态

     uCheck:MF_BYCOMMAND - uIDCheckItem参数必须填写菜单项ID

                  MF_POSITION - uIDCheckItem参数必须填写菜单项位置

                  MF_CHECKED - 菜单项勾选

                  MF_UNCHECKED - 菜单项非勾选                  

     //设置菜单项可用/不可用/灰色状态

     BOOL EnableMenuItem( HMENU  hMenu,              //菜单句柄

                                                UINT      uIDEnableItem,  //菜单项ID或位置(索引)

                                                UINT      uEnable);          //具体状态

     uEnable:MF_BYCOMMAND - uIDEnableItem参数必须填写菜单项ID

                   MF_POSITION - uIDEnableItem参数必须填写菜单项位置

                            MF_DISABLE - 不可用

                            MF_ENABLE - 可用

                            MF_GRAYED - 灰色状态

     函数使用时,需要通过设置MF_BYPOSITION或者MF_BYCOMMAND,确定使用菜单索引号或者菜单ID。

  (5)WM_INITMENUPOPUP

     在菜单被激活但为显示时,窗口会收到这个消息 

     wPARAM:即将显示的菜单句柄

     lPARAM:LOWORD - 被点击顶层菜单索引(位置)       

                            HIWORD - 即将显示菜单是否为窗口菜单

     窗口菜单:顶层菜单/系统菜单属于窗口菜单,弹出式菜单不属于窗口菜单。

  相关示例代码: 

#include "stdafx.h"
#include "stdio.h"

HINSTANCE g_hInstance = 0;  //接收当前程序实例句柄
HMENU hFile = 0;
HANDLE g_hOutput = 0;

void OnCreate(HWND hWnd)
{
    //创建(顶层)菜单
    HMENU hMain = CreateMenu();

    //创建下拉菜单
    hFile = CreatePopupMenu();
    AppendMenu(hFile, MF_STRING|MF_CHECKED, 1003, "新建");
    AppendMenu(hFile, MF_SEPARATOR, 0, "");
    AppendMenu(hFile, MF_STRING|MF_MENUBARBREAK, 1004, "退出");
    HMENU hHelp = CreatePopupMenu();
    AppendMenu(hHelp, MF_STRING|MF_GRAYED, 1005, "关于");

    //添加菜单项
    //MF_POPUP风格的菜单被点击后才会弹出菜单,而且第三个参数必须为下拉菜单的句柄
    AppendMenu(hMain, MF_POPUP, (UINT)hFile, "文件");
    AppendMenu(hMain, MF_POPUP, (UINT)hHelp, "帮助");
    //将菜单设置到窗口
    SetMenu(hWnd, hMain);
}
int g_state = 0;//标志量(标识新建菜单项当前状态)
void OnCommand(HWND hWnd, WPARAM wParam)
{
    switch (LOWORD(wParam))
    {
    case 1003:
        if (0 == g_state)
        {
            CheckMenuItem(hFile, 1003, MF_BYCOMMAND | MF_UNCHECKED);
        }
        else
        {
            CheckMenuItem(hFile, 0, MF_BYPOSITION | MF_CHECKED);
        }
        g_state = !g_state;
        break;
    case 1004:
        MessageBox(hWnd, "退出被点击", "Info", MB_OK);
        break;
    case 1005:
        MessageBox(hWnd, "关于被点击", "Info", MB_OK);
        break;
    default:
        break;
    }
}
void OnInitMenuPopup(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    char szText[256] = { 0 };
    sprintf_s(szText, "即将显示菜单的句柄:%d,被点击的菜单项位置:%d,是否为窗口菜单:%d
",
        wParam, LOWORD(lParam), HIWORD(lParam));
    WriteConsole(g_hOutput, szText, strlen(szText), NULL, NULL);
}
//窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_INITMENUPOPUP:
        OnInitMenuPopup(hWnd, wParam, lParam);
        break;
    case WM_COMMAND:
        OnCommand(hWnd, wParam);
        break;
    case WM_CREATE:
        OnCreate(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}
//注册窗口类
BOOL Register(LPSTR lpClassName, WNDPROC wndProc)
{
    WNDCLASSEX wce = { 0 };

    wce.cbSize = sizeof(wce);
    wce.cbClsExtra = 200;
    wce.cbClsExtra = 200;
    wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wce.hCursor = NULL;
    wce.hIcon = NULL;
    wce.hIconSm = NULL;
    wce.hInstance = g_hInstance;
    wce.lpfnWndProc = wndProc;
    wce.lpszClassName = lpClassName;
    wce.lpszMenuName = NULL;
    wce.style = CS_HREDRAW | CS_VREDRAW;

    ATOM nAtom = RegisterClassEx(&wce);
    if (0 == nAtom)
    {
        return FALSE;
    }
    return TRUE;
}
//创建主窗口
HWND CreateMainWindow(LPSTR lpClassName, LPSTR lpWndName)
{
    HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, g_hInstance, NULL);
    return hWnd;
}
//创建子窗口
HWND CreateChildWindow(LPSTR lpClassName, LPSTR lpWndName, HWND hParent)
{
    HWND hChild = CreateWindowEx(0, lpClassName, lpWndName, WS_CHILD | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        100, 100, 200, 200, hParent, NULL, g_hInstance, NULL);
    return hChild;
}
//显示窗口
void Display(HWND hWnd)
{
    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);
}
//消息循环
void Message()
{
    MSG nMsg = { 0 };
    while (GetMessage(&nMsg, NULL, 0, 0))
    {
        TranslateMessage(&nMsg);
        DispatchMessage(&nMsg);
    }
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    AllocConsole();
    g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    g_hInstance = hInstance;
    Register("Main", WndProc);
    HWND hWnd = CreateMainWindow("Main", "window");
    Display(hWnd);
    Message();

    return 0;
}
View Code

  运行结果:

    

  (6)系统菜单

     系统菜单的获取:HMENU GetSystemMenu( HWND hWnd,      //窗口句柄

                                                                         BOOL  bRevert);  //重置选项

     返回获取到的系统菜单句柄

       bRevert:TRUE - 删除旧菜单,恢复到默认的系统菜单

                              FALSE - 返回当前的系统菜单句柄

     系统菜单的修改:AppendMenu

                                 DeleteMenu( HMENU  hMenu,     //菜单句柄

                                                       UINT     uPosition,  //菜单项ID或位置

                                                       UINT     uFlags);    //决定uPosition参数填写什么

     系统菜单命令响应:

                通过WM_SYSCOMMAND响应菜单命令。

                    wPARAM:LOWORD - 命令ID

  相关示例代码:

#include "stdafx.h"

HINSTANCE g_hInstance = 0;  //接收当前程序实例句柄

void OnCreate(HWND hWnd)
{
    HMENU hSys = GetSystemMenu(hWnd, FALSE);
    for (int i = 0; i < 6; i++)
    {
        DeleteMenu(hSys, 0, MF_BYPOSITION);
    }
    AppendMenu(hSys, MF_SEPARATOR, 0, "");
    AppendMenu(hSys, MF_STRING, 1001, "我的菜单项");
}
void OnSysCommand(HWND hWnd, WPARAM wParam)
{
    switch (LOWORD(wParam))
    {
    case 1001:
        MessageBox(hWnd, "我的菜单项被点击", "Info", MB_OK);
        break;
    }
}
//窗口处理函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_SYSCOMMAND:
        OnSysCommand(hWnd, wParam);
        break;
    case WM_CREATE:
        OnCreate(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}
//注册窗口类
BOOL Register(LPSTR lpClassName, WNDPROC wndProc)
{
    WNDCLASSEX wce = { 0 };

    wce.cbSize = sizeof(wce);
    wce.cbClsExtra = 200;
    wce.cbClsExtra = 200;
    wce.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wce.hCursor = NULL;
    wce.hIcon = NULL;
    wce.hIconSm = NULL;
    wce.hInstance = g_hInstance;
    wce.lpfnWndProc = wndProc;
    wce.lpszClassName = lpClassName;
    wce.lpszMenuName = NULL;
    wce.style = CS_HREDRAW | CS_VREDRAW;

    ATOM nAtom = RegisterClassEx(&wce);
    if (0 == nAtom)
    {
        return FALSE;
    }
    return TRUE;
}
//创建主窗口
HWND CreateMainWindow(LPSTR lpClassName, LPSTR lpWndName)
{
    HWND hWnd = CreateWindowEx(0, lpClassName, lpWndName, WS_OVERLAPPEDWINDOW,
        100, 100, 500, 300, NULL, NULL, g_hInstance, NULL);
    return hWnd;
}
//显示窗口
void Display(HWND hWnd)
{
    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);
}
//消息循环
void Message()
{
    MSG nMsg = { 0 };
    while (GetMessage(&nMsg, NULL, 0, 0))
    {
        TranslateMessage(&nMsg);
        DispatchMessage(&nMsg);
    }
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    g_hInstance = hInstance;
    Register("Main", WndProc);
    HWND hWnd = CreateMainWindow("Main", "window");
    Display(hWnd);
    Message();

    return 0;
}
View Code

  运行结果:

    

    

原文地址:https://www.cnblogs.com/csqtech/p/5609013.html