VS学习笔记 菜单

1.在资源视图中可以找到MENU中的IDR_MAINFRAME中添加一个menu
  只要在属性中选择popup为false就可以输入ID号:IDM_TEST


2.对应的添加OnTest来响应该资源


3.在不同类增加对该资源的命令响应函数,view->doc>mainframe->app按这样的

先后顺序进行响应。在不是从cwnd派生的类中不能直接使用Messagebox,而要使用
Afx前缀。

void CMainFrame::OnTest()
{
	// TODO: 在此添加命令处理程序代码
    MessageBox(TEXT("MainFrame Clicked!"));
}


void CMenuApp::OnTest()
{
	// TODO: 在此添加命令处理程序代码
	AfxMessageBox(TEXT("App Clicked!!"));
}

4.消息的分类
(1)标准消息:除了WM_COMMAND之外,WM_开头的消息,从CWnd派生的类都可以收到这类消息。
(2)命令消息:来自菜单,加速键,工具栏的消息,这类消息以WM_COMMAND呈现。
在MFC中,通过菜单项的标示ID来区分不同的命令消息。在SDK中以消息的wparam来识别。
从CCMDTARGET派生的类,都可以接受到这类消息。
(3)通道消息:由控件产生的消息,例如按钮的淡季,列表框的选择。为的是向父窗口通知事件的发生。
这类消息也是以WM_COMMAND呈现,从CCMDTARGET类派生的类可以接受这类消息。


因此DOC类app类都是CCmdTarget类派生的,CWnd类也是从CCMdTarget派生的。


5.命令消息的路由
AfxWndProc->AfxCallWndProc->WindowProc(CWnd的成员函数)->OnWndMessage(判断到来的消息是什么消息)
如果是命令消息会交由OnCommand处理,如果是通道消息则用OnNodify处理。最后都调用OnCmdMsg进行处理


6.OnCommand进行路由:CmainFrame收到命令消息先交给子窗口CView,Cview搜索不到处理命令,
View类交给Doc,Doc搜索,如果没有则Doc交回给view,view交回给CMainFrame,
Cmainframe搜索自己的成员函数,如果仍没找到就交给app类。


7.菜单的结构
GetMenu返回的是指向整个菜单栏的指针(CMenu *)
GetSubMenu返回的是指向子菜单的指针(CMenu *)
CheckMenuItem 放置或移走一个标记。


8.找到对应的菜单项添加标记。
可以用位置来表示这个菜单项也可以用ID号来表示这个菜单项。
GetMenu()->GetSubMenu(0)->CheckMenuItem(0,MF_BYPOSITION | MF_CHECKED);
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND | MF_CHECKED);

9.设置一个缺省的MENUITEM:菜单项以粗体显示.
GetMenu()->GetSubMenu(0)->SetDefaultItem(1,TRUE);

分隔栏会计算索引位置因此打印是5,一个子菜单下不能有两个粗体菜单(缺省菜单)
GetMenu()->GetSubMenu(0)->SetDefaultItem(5,TRUE);

10.图形标记菜单
m_bitmap.LoadBitmapW(IDB_BITMAP1);
GetMenu()->GetSubMenu(0)->SetMenuItemBitmaps(0,MF_BYPOSITION,&m_bitmap,&m_bitmap);
CString str;
str.Format(TEXT("x=%d,y=%d"),GetSystemMetrics(SM_CXMENUCHECK),GetSystemMetrics(SM_CYMENUCHECK));
MessageBox(str);//获取系统的menu大小来设置位图的大小

11.屏蔽一个菜单项 必须在构造函数中如下设置
CMainFrame::CMainFrame()
{
	// TODO: 在此添加成员初始化代码
	m_bAutoMenuEnable = FALSE;
}
GetMenu()->GetSubMenu(0)->EnableMenuItem(1,MF_BYPOSITION | MF_DISABLED |MF_GRAYED);

12.菜单项销毁和建立
SetMenu(NULL);
当menu是一个局部变量时,需要调用detach把句柄HMENU和当前的对象断开
CMenu menu;
menu.LoadMenu(IDR_MAINFRAME);
SetMenu(&menu);
menu.Detach();

13.菜单命令更新机制
利用MFC编程,菜单项状态的维护依赖于CN_UPDATE_COMMAND_UI消息。
我们可以通过手工,或利用ClassWizard在消息映射中ON_UPDATE_COMMAND_UI宏来捕获CN_UPDATE_COMMAND_UI消息。
 
当为菜单项添加一个UPDATE_COMMANG_UI消息响应函数,MFC在后台所做的工作是:
当要显示菜单时,操作系统发出WM_INITMENUPOPUP消息,
然后由程序窗口的基类如CframeWnd接管。它会创建一个CcmdUI对象,并与程序的第一个菜单项关联,
调用该对象的一个成员函数DoUpdate()。这个函数发出CN_UPDATE_COMMAND_UI消息,这条消息带有一个指向CcmdUI对象的指针。
这时,系统会判断是否存在一个ON_UPDATE_COMMAND_UI宏去捕获这个菜单项消息。
如果找到一个这样的宏,就调用相应的消息响应函数进行处理,
在这个函数中,可以利用传递过来的CcmdUI对象去调用相应的函数,使该菜单项可以使用,或禁用该菜单项。
当更新完第一个菜单项后,同一个CcmdUI对象就设置为与第二个菜单项相关联,依此顺序进行,直到完成所有菜单项的处理。这就是MFC采用的命令更新机制。
因为工具栏和菜单栏的索引不一样,所以为保证二者状态一致,最好采用菜单项标识或工具栏按钮标识的方式来进行设置。


比如在资源menu中,右键剪切菜单项,添加一个UPDATE_COMMAND_UI的处理程序
void CMainFrame::OnUpdateEditCut(CCmdUI *pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->Enable();
}

14.快捷菜单
(1)VS2010只能手动添加,新建一个menu。
(2)在VIEW类增加响应WM_RBOTTOMDOWN的函数。
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CMenu menu;
	menu.LoadMenu(IDR_NINO);
	CMenu *pPopup = menu.GetSubMenu(0);


	ClientToScreen(&point);//屏幕坐标换算到窗口内坐标


	pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this); 


	CView::OnRButtonDown(nFlags, point);
}


(3)对菜单项进行响应,添加响应ID_NINO_RIGHT的消息处理函数
void CMenuView::OnNinoRight()
{
	// TODO: 在此添加命令处理程序代码
	MessageBox(TEXT("nino is right!!"));
}

15.添加菜单:创建一个弹出菜单,并添加到菜单栏末尾;
插入菜单:在指定位置插入。
删除菜单:指定位置删除。
	CMenu menu;
	menu.CreatePopupMenu();
	//GetMenu()->AppendMenuW(MF_POPUP,(UINT)menu.m_hMenu,TEXT("周天"));
	GetMenu()->InsertMenu(2,MF_BYPOSITION | MF_POPUP,(UINT)menu.m_hMenu,TEXT("工具"));
	menu.AppendMenu(MF_STRING,111,TEXT("HELLO"));
	menu.AppendMenu(MF_STRING,112,TEXT("WORLD"));
	menu.Detach();
	GetMenu()->GetSubMenu(0)->AppendMenu(MF_STRING,113,TEXT("WELCOME"));
	GetMenu()->GetSubMenu(0)->InsertMenu(ID_FILE_OPEN,MF_BYCOMMAND | MF_STRING,114,TEXT("INSERT"));
	GetMenu()->DeleteMenu(1,MF_BYPOSITION);
	GetMenu()->GetSubMenu(0)->DeleteMenu(2,MF_BYPOSITION);

16.响应菜单项
menu.AppendMenu(MF_STRING,IDM_HELLO,TEXT("HELLO"));
要对HELLO菜单项添加响应,有三步骤
(1)头文件中:
// 生成的消息映射函数
protected:
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnHello();
	DECLARE_MESSAGE_MAP()

(2)消息映射:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	ON_WM_CREATE()
	ON_COMMAND(IDM_HELLO,OnHello)
END_MESSAGE_MAP()

(3)消息处理函数
// CMainFrame 消息处理程序
void CMainFrame::OnHello()
{
	MessageBox(TEXT("Hello!!"));
}

17.电话本的操作
void CMENU2View::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CClientDC dc(this);
	if(0x0d == nChar)
	{
		if(0 == ++m_nIndex)
		{
			m_menu.CreatePopupMenu();
			GetParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)m_menu.m_hMenu,TEXT("PhoneBook"));
		    GetParent()->DrawMenuBar();
		}
		m_menu.AppendMenu(MF_STRING,IDM_PHONE1+m_nIndex,m_string.Left(m_string.Find(' ')));
		m_strArray.Add(m_string);
		m_string.Empty();
		Invalidate(TRUE);//重绘时擦除内容
	}
	else
	{
		m_string += (char)nChar;
		dc.TextOut(0,0,m_string);
	}
	CView::OnChar(nChar, nRepCnt, nFlags);
}




void CMENU2View::OnPhone1()
{
	// TODO: 在此添加命令处理程序代码
	CClientDC dc(this);
	dc.TextOutW(0,0,m_strArray.GetAt(0));
}




void CMENU2View::OnPhone2()
{
	// TODO: 在此添加命令处理程序代码
	CClientDC dc(this);
	dc.TextOutW(0,0,m_strArray.GetAt(1));
}




void CMENU2View::OnPhone3()
{
	// TODO: 在此添加命令处理程序代码
	CClientDC dc(this);
	dc.TextOutW(0,0,m_strArray.GetAt(2));
}


18.增加虚函数来截获本该由VIEW类来执行的响应。


BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
	// TODO: 在此添加专用代码和/或调用基类
	int MenuCmdId = LOWORD(wParam);
	CMENU2View *pView = (CMENU2View *)GetActiveView();
	if(MenuCmdId>=IDM_PHONE1 &&  MenuCmdId< IDM_PHONE1+ pView->m_strArray.GetSize())
	{
		CClientDC dc(pView);
		dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1));
		//MessageBox(TEXT("TEST"));
		return TRUE;
	}
	return CFrameWnd::OnCommand(wParam, lParam);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值