【MFC】菜单

【MFC】菜单

# 菜单简述

Windows 的菜单分为两类:

窗口菜单

弹出式菜单

窗口菜单是挂接到窗口上的;

弹出式菜单是根据程序设计者的需要在某处弹出的。

# 添加菜单资源

右键 项目 , 添加 -> 资源

选择 Menu ,点击 新建 ,进入资源编辑界面。

顶层菜单 (类型为窗口菜单) 添加一个项 新建 、顶层的子菜单 (类型为弹出式菜单) 添加一个项 文件

修改顶层菜单的资源为 IDR_MENU_TOP

修改顶层菜单的 新建 项的子菜单的 文件 项的资源为 ID_MENU_FILE_NEW 。

注:此处附注的菜单类型并不需要你在编辑时设置,是指明该菜单属于什么类型。

顶层菜单的类型就是 窗口菜单

顶层菜单的子菜单的类型就是 弹出式菜单

资源编辑界面示范:

# 使用窗口菜单

代码示例

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include #include "resource.h"class CMyFrameWnd :public CFrameWnd { DECLARE_MESSAGE_MAP()public: afx_msg int OnCreate(LPCREATESTRUCT pCs); afx_msg void OnClose(); afx_msg void OnMenu_File_New();private: CMenu* m_pMenu;};BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() ON_WM_CLOSE() ON_COMMAND(ID_MENU_FILE_NEW, OnMenu_File_New)END_MESSAGE_MAP()afx_msg int CMyFrameWnd::OnCreate(LPCREATESTRUCT pCs) { m_pMenu = new CMenu; m_pMenu->LoadMenu(IDR_MENU_TOP); SetMenu(m_pMenu); return CFrameWnd::OnCreate(pCs);}afx_msg void CMyFrameWnd::OnClose() { if (m_pMenu) { delete m_pMenu; m_pMenu = nullptr; } CFrameWnd::OnClose();}afx_msg void CMyFrameWnd::OnMenu_File_New() { AfxMessageBox(L"new");}class CMyWinApp :public CWinApp {public: CMyWinApp() { } virtual BOOL InitInstance() { CMyFrameWnd* frame = new CMyFrameWnd; frame->Create(nullptr, L"MFCBase"); m_pMainWnd = frame; frame->ShowWindow(SW_SHOW); frame->UpdateWindow(); return TRUE; }};CMyWinApp g_theApp;

代码想必读者也比较熟悉了,有一些需要注意的改动如下:

CMyFrameWnd 添加私有成员 CMenu* m_pMenu ;

添加了一个新的消息映射条目 ON_COMMAND(ID_MENU_FILE_NEW, OnMenu_File_New) ;

为消息映射函数添加了宏 afx_msg ;

并无特殊作用,仅为提高代码可读性。

# 挂接窗口菜单

CMyFrameWnd::OnCreate

首先,代码中 new 了一个 CMenu 类对象,使我们添加的私有成员指向它,这是 MFC 封装的菜单类。

其次,调用了 CMenu::LoadMenu ,用于加载我们添加的菜单资源。

最后,以当前 CMyFrameWnd 类对象的身份,调用了 CFrameWnd::SetMenu 成员函数。

至此,我们完成了将窗口菜单挂接到 CMyFrameWnd 类对象上的工作。

# 处理菜单项回调事件

ON_COMMAND(ID_MENU_FILE_NEW, OnMenu_File_New)

CMyFrameWnd::OnMenu_File_New

只需要通过 ON_COMMAND 宏,就可以建立指定菜单资源被点击 ( WM_COMMAND 消息) 与回调函数的映射。

# WM_COMMAND

命令消息,在菜单被点击等事件发生时产生。

在 MFC 的消息处理架构中, WM_COMMAND 的处理流程与我们先前接触的 WM_CREATE 等消息是不同的。

我们回到 CWnd::OnWndMsg 函数,在函数开始部分就能看到相关源码。

代码示例

1234567891011121314151617BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult){ LRESULT lResult = 0; union MessageMapFunctions mmf; mmf.pfn = 0; CInternalGlobalLock winMsgLock; // special case for commands if (message == WM_COMMAND) { if (OnCommand(wParam, lParam)) { lResult = 1; goto LReturnTrue; } return FALSE; } ...

只要是 WM_COMMAND 消息,会调用 CWnd::OnCommand ,返回后就再次返回了。

最终会走到全局静态函数 _AfxDispatchCmdMsg 中回调 CMyFrameWnd::OnMenu_File_New 。

由于代码较为繁琐,故不再向下深入,读者感兴趣可以自行调试。

# 使用弹出式菜单

# WM_CONTEXTMENU

DefWindowProc 在处理 WM_RBUTTONUP 或 WM_NCRBUTTONUP 消息,或是用户键入 SHIFT+F10 时,生成 WM_CONTEXTMENU 消息。

# 实现右键客户区弹出菜单

我们知道,在菜单编辑界面中,顶层菜单的子菜单都是独立的弹出式菜单;

故这些子菜单都是可以被单独弹出的

而顶层菜单项被点击时弹出子菜单不需要我们处理,是因为 windows 替我们做好了相关的工作。

接下来我们通过映射 WM_CONTEXTMENU 消息,实现在客户区右键,弹出顶层菜单 文件 的子菜单。

代码示例

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667#include #include "resource.h"class CMyFrameWnd :public CFrameWnd { DECLARE_MESSAGE_MAP()public: afx_msg int OnCreate(LPCREATESTRUCT pCs); afx_msg void OnClose(); afx_msg void OnMenu_File_New(); afx_msg void OnContextMenu(CWnd* wnd, CPoint pos);private: CMenu* m_pMenu;};BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() ON_WM_CLOSE() ON_COMMAND(ID_MENU_FILE_NEW, OnMenu_File_New) ON_WM_CONTEXTMENU()END_MESSAGE_MAP()afx_msg int CMyFrameWnd::OnCreate(LPCREATESTRUCT pCs) { m_pMenu = new CMenu; m_pMenu->LoadMenu(IDR_MENU_TOP); SetMenu(m_pMenu); return CFrameWnd::OnCreate(pCs);}afx_msg void CMyFrameWnd::OnClose() { if (m_pMenu) { delete m_pMenu; m_pMenu = nullptr; } CFrameWnd::OnClose();}void CMyFrameWnd::OnContextMenu(CWnd* wnd, CPoint pos) { CMenu* pNewMenu = m_pMenu->GetSubMenu(0); pNewMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, pos.x, pos.y, wnd);}afx_msg void CMyFrameWnd::OnMenu_File_New() { AfxMessageBox(L"new");}class CMyWinApp :public CWinApp {public: CMyWinApp() { } virtual BOOL InitInstance() { CMyFrameWnd* frame = new CMyFrameWnd; frame->Create(nullptr, L"MFCBase"); m_pMainWnd = frame; frame->ShowWindow(SW_SHOW); frame->UpdateWindow(); return TRUE; }};CMyWinApp g_theApp;

代码并不复杂,建议读者自行尝试调试运行。

参考资料:

https://www.cnblogs.com/hanford/p/6163690.html

https://www.cnblogs.com/greenleaf1976/p/16460330.html

🎊 相关推荐

dnf厄运套怎么做
365账号限制投注怎么办

dnf厄运套怎么做

📅 08-01 👀 7858
“胸”态百出 看看那些世界杯豪放女球迷
男性射精健康指南:正常机制、常见问题与科学保养策略