MFC 菜单

发布时间:2023年12月24日

目录

MFC菜单

菜单使用

添加菜单资源

将菜单设置到窗口

ON_COMMAND消息处理

命令消息 WM_COMMAND 的处理顺序

设置菜单项状态

右键菜单


MFC菜单

在Win32编程中,使用菜单句柄 HMENU 来标识菜单,在MFC中使用CMenu类对象表示菜单。封装了关于菜单的各种操作成员函数,另外还封装了一个非常重要的成员变量m_hMenu(菜单句柄)

菜单使用

(1)添加菜单资源

(2)将菜单设置到窗口

  • 利用pFrame调用Create函数时,传参。
  • 在处理框架窗口的WM_CREATE消息时
    • CMenu menu ;? ?// 完成菜单句柄加载到菜单对象里,并且完成对象句柄绑定
    • menu.LoadMenu(...); // 使用句柄设置为窗口的菜单

添加菜单资源

添加一个菜单

修改 新建 ID 为 ID_NEW

将菜单设置到窗口

方式一:利用pFrame调用Create函数时,传参。

pFrame->Create(NULL,"MFCCreate",WS_OVERLAPPEDWINDOW,CFrameWnd::rectDefault,NULL,(char*)IDR_MENU1);

根据提供的参数,Create() 函数的参数含义如下:

  • 第一个参数?NULL?表示窗口的父窗口为默认值,即没有父窗口。
  • 第二个参数?"MFCCreate"?是窗口的标题,将显示在窗口的标题栏上。
  • 第三个参数?WS_OVERLAPPEDWINDOW?是窗口的样式标志,表示创建一个具有标题栏、边框和控制菜单的重叠窗口。
  • 第四个参数?CFrameWnd::rectDefault?是窗口的初始位置和大小。CFrameWnd::rectDefault?是一个常量,表示使用默认的大小和位置。
  • 第五个参数?NULL?表示没有指定父窗口,因为这是一个顶级窗口。
  • 第六个参数?(char*)IDR_MENU1?是窗口的菜单资源标识符,用于关联窗口的菜单。

此时新建这个下拉菜单是灰色的,无法点击。这是因为店家这个菜单的消息没被处理

方式二;在处理框架窗口的WM_CREATE消息时

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
	menu.LoadMenu(IDR_MENU1);
	this->SetMenu( &menu );// 等价与 ::SetMenu(this->m_hWnd, menu.m_hMenu);
	return CFrameWnd::OnCreate(pcs);
}

调用类的成员函数本质还是调用Win32 API?

代码说明:可以实现将指定的菜单资源加载到窗口,并将其设置为窗口的菜单,以便在窗口中显示和处理菜单项的相关操作。?

  • 调用 LoadMenu(IDR_MENU1) 函数,将菜单资源 IDR_MENU1 加载到 menu 对象中。本质还是调用Win32 API
  • 通过调用 ::SetMenu(this->m_hWnd, menu.m_hMenu) 函数,将 menu 对象的菜单句柄 m_hMenu 设置为当前窗口的菜单。

值得注意的是,菜单对象应该作为框架窗口对象成员变量

LoadMenu内部代码,通过菜单ID拿到菜单句柄,把句柄和菜单对象绑定

_AFXWIN_INLINE BOOL CMenu::LoadMenu(UINT nIDResource)
	{ return Attach(::LoadMenuW(AfxFindResourceHandle(
		MAKEINTRESOURCE(nIDResource), RT_MENU), MAKEINTRESOURCEW(nIDResource))); }

attach函数:

把菜单句柄赋值给对象成员变量

调用SetPermanent函数把句柄绑定到菜单对象

BOOL CMenu::Attach(HMENU hMenu)
{
	ASSERT(m_hMenu == NULL);        // only attach once, detach on destroy
	if (hMenu == NULL)
	{
		return FALSE;
	}
    
	// Capture menu in object first to ensure it does not leak if the map cannot be allocated/expanded 
	m_hMenu=hMenu;

	CHandleMap* pMap = afxMapHMENU(TRUE); // create map if not exist
	ASSERT(pMap != NULL);
	pMap->SetPermanent(m_hMenu, this);
	return TRUE;
}

通过菜单句柄就能拿到菜单对象?

inline void CHandleMap::SetPermanent(HANDLE h, CObject* permOb)
	{ m_permanentMap[(LPVOID)h] = permOb; }

ON_COMMAND消息处理

可以在MSDN中搜索 ON_COMMAND 就可以找到 WM_COMMAND 消息的处理

在框架窗口的消息映射中处理,ON_COMMAND(菜单项ID,处理消息的函数名)

void CMyFrameWnd::OnNew() {
	AfxMessageBox("框架类处理了新建菜单项被点击");
}

命令消息 WM_COMMAND 的处理顺序

框架类比应用程序类先处理 WM_COMMAND 消息

在应用程序类中也处理 WM_COMMAND 消息,框架类处理完后,其他的就不处理了,只处理一次

对比系统消息,如WM_CREATE只在框架窗口类处理。只有WM_COMMAND会在多个类的中处理

设置菜单项状态

需要处理消息 WM_INITMENUPOPUP 菜单激活,即将显示还没显示,可以调用两个API:CheckMenuItem 、 EnableMenuItem 处理。在MFC中也是要处理这个消息?

void CMyFrameWnd::OnInitMenuPopup(CMenu* pPopup, UINT nPos, BOOL i) {
	//	pPopup->CheckMenuItem( ID_NEW, MF_CHECKED );
	::CheckMenuItem(pPopup->m_hMenu, ID_NEW, MF_CHECKED);
}

右键菜单

右键菜单即是上下文菜单,右击鼠标可以显示一个类似Win右击鼠标可以显示刷新一样

WM_CONTEXTMENU? ? API:::TrackPopupMenu

ON_WM_CONTEXTMENU? 成员函数:CMenu::TrackPopupMenu

菜单是包含两个部分,也就是说CMenu对象是整个菜单

void CMyFrameWnd::OnContextMenu(CWnd* pWnd, CPoint pt) {
	//	HMENU hPopup = ::GetSubMenu(menu.m_hMenu,0);
	//	::TrackPopupMenu( hPopup, TPM_LEFTALIGN|TPM_TOPALIGN, pt.x, pt.y,
	//										0, this->m_hWnd, NULL );
	CMenu* pPopup = menu.GetSubMenu(0);
	pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_TOPALIGN, pt.x, pt.y, this);
}

TrackPopupMenu函数只能显示弹出式菜单,需要先拿到对应的句柄,调用GetSubMenu函数,参数0表示”文件“,可以拿到文件菜单的下拉菜单

  • TPM_LEFTALIGN?将菜单左对齐,即菜单的左边缘与触发菜单的点对齐。
  • TPM_TOPALIGN?将菜单上对齐,即菜单的上边缘与触发菜单的点对齐。

文章来源:https://blog.csdn.net/qq_61553520/article/details/135115069
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。