荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Second (石开), 信区: Program
标  题: 3.3 使用菜单
发信站: 荔园晨风BBS站 (Wed May 30 01:18:41 2001), 转信

3.3 使用菜单

利用菜单接受用户命令是一中很简单的交互方法,同时也是一种很有效的方法。通常菜
单作为一中资源存储在文件中,因此我们可以在设计时就利用资源编辑器设计好一个菜
单。关于使用VC设计菜单我就不再多讲了,但你在编写菜单时应该尽量在属性对话框的
底部提示(Prompt)处输入文字,这虽然不是必要的,但MFC在有状态栏和工具条的情况
下会使用该文字,文字的格式为“状态栏出说明\n工具条提示”。图33_g1

我们要面临的任务是如何知道用户何时选择了菜单,他选的是什么菜单项。当用户选择
了一个有效的菜单项时系统会向应用发送一个WM_COMMAND消息,在消息的参数中表明来
源。在MFC中我们只需要进行一次映射,将某一菜单ID映射到一处理函数,图33_g2。在
这里我们在CView的派生类中处理菜单消息,同时我对同一ID设置两个消息映射,接下来
将这两种映射的作用。

ON_COMMAND 映射的作用为在用户选择该菜单时调用指定的处理函数。如:ON_COMMAND(
IDM_COMMAND1, OnCommand1)会使菜单被选择时调用OnCommand1成员函数。
ON_UPDATE_COMMAND_UI(IDM_COMMAND1, OnUpdateCommand1) 映射的作用是在菜单被显示
时通过调用指定的函数来进行确定其状态。在这个处理函数中你可以设置菜单的允许/禁
止状态,其显示字符串是什么,是否在前面打钩。函数的参数为CCmdUI* pCmdUI,CCmd
UI是MFC专门为更新命令提供的一个类,你可以调用

Enable 设置允许/禁止状态
SetCheck 设置是否在前面打钩
SetText 设置文字

下面我讲解一个例子:我在CView派生类中有一个变量m_fSelected,并且在视中处理两
个菜单的消息,当IDM_COMMAND1被选时,对m_fSelected进行逻辑非操作,当IDM_COMMA
ND2被选中时出一提示;同时IDM_COMMAND1根据m_fSelected决定菜单显示的文字和是否
在前面打上检查符号,IDM_COMMAND2根据m_fSelected的值决定菜单的允许/禁止状态。
下面是代码和说明:
void CMenuDView::OnCommand1()
{
 m_fSelected=!m_fSelected;
 TRACE("command1 selected\n");
}
void CMenuDView::OnUpdateCommand1(CCmdUI* pCmdUI)
{
 pCmdUI->SetCheck(m_fSelected);//决定检查状态
 pCmdUI->SetText(m_fSelected?"当前被选中":"当前未被选中");//决定所显示的文字

}
void CMenuDView::OnUpdateCommand2(CCmdUI* pCmdUI)
{//决定是否为允许
 pCmdUI->Enable(m_fSelected);
}
void CMenuDView::OnCommand2()
{//选中时给出提示
 AfxMessageBox("你选了command2");
}

接下来再讲一些通过代码操纵菜单的方法,在MFC中有一个类CMenu用来处理和菜单有关
的功能。在生成一个CMenu对象时你需要从资源中装如菜单,通过调用BOOL CMenu::Loa
dMenu( UINT nIDResource )进行装入,然后你就可以对菜单进行动态的修改,所涉及到
的函数有:
CMenu* GetSubMenu( int nPos ) 一位置得到子菜单的指针,因为一个CMenu对象只能表

示一个弹出菜单,如果菜单中的某一项也为弹出菜单,就需要通过该函数获取指针。
BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NUL
L ) 在末尾添加一项,nFlag为MF_SEPARATOR表示增加一个分隔条,这样其他两个参数将
会被忽略;为MF_STRING表示添加一个菜单项uIDNewItem为该菜单的ID命令值;为MF_PO
PUP表示添加一个弹出菜单项,这时uIDNewItem为另一菜单的句柄HMENU。lpszNewItem为
菜单文字说明。
BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR l
pszNewItem = NULL )用于在指定位置插入一菜单,位置由变量nPosition指明。如果nF
lags包含MF_BYPOSITION则表明插入在nPosition位置,如果包含MF_BYCOMMAND表示插入
在命令ID为nPosition的菜单处。
BOOL ModifyMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, LPCTSTR l
pszNewItem = NULL )用于修改某一位置的菜单,如果nFlags包含MF_BYPOSITION则表明
修改nPosition位置的菜单,如果包含MF_BYCOMMAND表示修改命令ID为nPosition处的菜
单。

BOOL RemoveMenu( UINT nPosition, UINT nFlags )用于删除某一位置的菜单。如果nF
lags包含MF_BYPOSITION则表明删除nPosition位置的菜单,如果包含MF_BYCOMMAND表示
删除命令ID为nPosition处的菜单。

BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp ) 和 BOOL
 InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pB
mp )可以添加一位图菜单,但这样的菜单在选中时只是反色显示,并不美观。(关于使
用自绘OwnerDraw菜单请参考我翻译的一篇文章自绘菜单类)
视图中是没有菜单的,在框架窗口中才有,所以只有用AfxGetApp()->m_pMainWnd->Get
Menu()才能得到应用的菜单指针。
最后我讲一下如何在程序中弹出一个菜单,你必须先装入一个菜单资源,你必需得到一
个弹出菜单的指针然后调用BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd
* pWnd, LPCRECT lpRect = NULL )弹出菜单,你需要指定(x,y)为菜单弹出的位置,pW
nd为接收命令消息的窗口指针。下面有一段代码说明方法,当然为了处理消息你应该在
pWnd指明的窗口中对菜单命令消息进行映射。
CMenu menu;
menu.LoadMenu(IDR_POPUP);
CMenu* pM=menu.GetSubMenu(0);
CPoint pt;
GetCursorPos(&pt);
pM->TrackPopupMenu(TPM_LEFTALIGN,pt.x,pt.y,this);

另一种做法是通过CMenu::CreatePopupMenu()建立一个弹出菜单,然后使用TrackPopup
Menu弹出菜单。使用CreatePopupMenu创建的菜单也可以将其作为一个弹出项添加另一个
菜单中。下面的伪代码演示了如何创建一个弹出菜单并进行修改后弹出:
CMenu menu1,menu2;
menu1.CreatePopupMenu
menu1.InsertMenu(1)
menu1.InsertMenu(2)
menu1.InsertMenu(3)
menu2.CreatePopupMenu
menu2.AppendMenu(MF_POPUP,1,menu1.Detach()) 将弹出菜单加入 or InsertMenu...
menu2.InsertMenu("string desc");
menu.TrackPopupMenu(...)

--
                            既然热爱生命
                            那么,
                            一切都在意料之中。

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.28.190]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店