您的位置:首页 > 其它

一个关于对话框中GetMenu的问题

2007-12-15 16:02 274 查看
一个对话框工程,我在OnInitDialog中创建了一个菜单,代码如下:
CMenu Menu,PopupMenu1,PopupMenu2;

Menu.CreateMenu();
PopupMenu1.CreatePopupMenu();
PopupMenu2.CreatePopupMenu();

PopupMenu2.AppendMenu(MF_STRING,IDC_POPMENU_VIEW_NORMALICON,"Large Icon");
PopupMenu2.AppendMenu(MF_STRING,IDC_POPMENU_VIEW_SMALLICON,"Small Icon");
PopupMenu2.AppendMenu(MF_STRING,IDC_POPMENU_VIEW_LIST,"List");
PopupMenu2.AppendMenu(MF_STRING,IDC_POPMENU_VIEW_DETAILS,"Detail");
PopupMenu2.AppendMenu(MF_STRING,IDC_POPMENU_VIEW_THUMBNAILS,"Thumbnail");

PopupMenu1.AppendMenu(MF_STRING,ID_FILE_NEW,"&New");
PopupMenu1.AppendMenu(MF_POPUP,(UINT)PopupMenu2.m_hMenu,"View");
PopupMenu1.AppendMenu(MF_STRING,ID_FILE_OPEN,"&Open");
PopupMenu1.AppendMenu(MF_STRING,ID_FILE_CLOSE,"&Close");
PopupMenu1.AppendMenu(MF_STRING,ID_APP_EXIT,"E&xit");

Menu.AppendMenu(MF_POPUP, (UINT)PopupMenu1.m_hMenu, "&File");
Menu.AppendMenu(MF_STRING, ID_EDIT_COPY, "&Edit");

SetMenu(&Menu);
然后我映射了WM_CONTEXTMENU消息,以便用户单击右键时能弹出“File”下的菜单,但是在第一步GetMenu可以执行,但是一旦调用GetSubMenu(0)后,ASSERT出错,不知什么原因。
我试过添加一个HMENU成员,在OnInitDialog退出之前使用Menu.Detach保存菜单句柄,然后在OnContextMenu中使用Attach,结果GetSubMenu(0)还是出错。
不知什么原因,请大家帮忙!谢谢。 问题点数:50、回复次数:12Top

1 楼isdong(有些事情应该忘记)回复于 2003-11-27 10:54:32 得分 30

BOOL CDialogDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// TODO: Add extra initialization here

CMenu Menu,PopupMenu1,PopupMenu2;

Menu.CreateMenu();
PopupMenu1.CreatePopupMenu();
PopupMenu2.CreatePopupMenu();

PopupMenu2.AppendMenu(MF_STRING,ID_FILE_NEW,"Large Icon");
PopupMenu2.AppendMenu(MF_STRING,ID_FILE_NEW,"Small Icon");
PopupMenu2.AppendMenu(MF_STRING,ID_FILE_NEW,"List");
PopupMenu2.AppendMenu(MF_STRING,ID_FILE_NEW,"Detail");
PopupMenu2.AppendMenu(MF_STRING,ID_FILE_NEW,"Thumbnail");

PopupMenu1.AppendMenu(MF_STRING,ID_FILE_NEW,"&New");
PopupMenu1.AppendMenu(MF_POPUP,(UINT)PopupMenu2.m_hMenu,"View");
PopupMenu1.AppendMenu(MF_STRING,ID_FILE_OPEN,"&Open");
PopupMenu1.AppendMenu(MF_STRING,ID_FILE_CLOSE,"&Close");
PopupMenu1.AppendMenu(MF_STRING,ID_APP_EXIT,"E&xit");

Menu.AppendMenu(MF_POPUP, (UINT)PopupMenu1.m_hMenu, "&File");
Menu.AppendMenu(MF_STRING, ID_EDIT_COPY, "&Edit");

SetMenu(&Menu);
Menu.Detach();
return TRUE; // return TRUE unless you set the focus to a control
}

void CDialogDlg::OnContextMenu(CWnd* pWnd, CPoint point)
{
CMenu Menu;
Menu.Attach(GetMenu()->m_hMenu);
CMenu * pMenu = Menu.GetSubMenu(0);

}
此代码可以正常执行Top

2 楼carbon107(<软件开发思想.h>)回复于 2003-11-27 11:01:13 得分 20

???不会吧,你是象楼上说的那样吗??
在OnContextMenu里
CMenu Menu;
Menu.Attach(GetMenu()->m_hMenu);
CMenu * pMenu = Menu.GetSubMenu(0);Top

3 楼codewarrior(会思考的草)回复于 2003-11-27 11:07:41 得分 0

to isdong(有些事情应该忘记) :
你的代码我试验过了,右键多点几次就会出错:(Top

4 楼codewarrior(会思考的草)回复于 2003-11-27 11:21:43 得分 0

试验过了,CMenu* pMenu = GetMenu();得到的确实是最上层那一行菜单的指针,但是为什么一调用GetSubMenu(0)就Debug Assertion Failed呢?Top

5 楼isdong(有些事情应该忘记)回复于 2003-11-27 11:27:42 得分 0

要保证正确必须如下
void CDialogDlg::OnContextMenu(CWnd* pWnd, CPoint point)
{
CMenu Menu;
Menu.Attach(GetMenu()->m_hMenu);
CMenu * pMenu = Menu.GetSubMenu(0);

Menu.Detach();
}
就是说这里,必须加上 Menu.Detach();
,相信你不难理解,只是你一时忘记了罢
Top

6 楼codewarrior(会思考的草)回复于 2003-11-27 11:34:45 得分 0

非也非也,我没有忘记。
刚刚发现GetMenu得到的根本就不是一个菜单!
你试试:
CMenu* pMenu = GetMenu();
ASSERT(pMenu);
ASSERT(::IsMenu(pMenu->GetSafeHmenu()));
Top

7 楼isdong(有些事情应该忘记)回复于 2003-11-27 11:42:46 得分 0

休息一下,关闭VC,重新打开工程,调试一下。我都试验了几十次了:),不会有问题的Top

8 楼codewarrior(会思考的草)回复于 2003-11-27 11:49:22 得分 0

现在问题明朗化了——就是——GetSubMenu(0)得到的不是一个popup Menu的句柄。
我现在的试验代码如下:void CTestDlg::OnContextMenu(CWnd* pWnd, CPoint point)
{
CMenu* pMenu = NULL;

ASSERT(::IsWindow(this->m_hWnd));<---没错确实是一个窗口,入口pWnd我这里没用到

pMenu = this->GetMenu();<--取最上层菜单
ASSERT(::IsMenu(pMenu->m_hMenu)); <--没错,确实是一个菜单的句柄

pMenu->AppendMenu(MF_STRING,ID_FILE_CLOSE,"hello");<--测试一下添几个项,成功.

// CMenu* pSub = pMenu->GetSubMenu(0);<--注释一去掉,ASSERT出错!!!
// ASSERT(::IsMenu(pSub->m_hMenu));

DrawMenuBar();
}

所以唯一的解释就是,GetSubMenu(0)得到的不是一个子菜单的句柄。但现在的问题是,如前代码所示(你也看到演示结果了),这是不可能的,因为第0位就是File菜单啊,下面肯定有子菜单的。
Top

9 楼codewarrior(会思考的草)回复于 2003-11-27 11:53:38 得分 0

刚才 CMenu* pMenu = GetMenu();
ASSERT(pMenu);
ASSERT(::IsMenu(pMenu->GetSafeHmenu()));
出错是因为我把前面OnInitDialog中的menu.detach给删了,不好意思我自己后来忘记了。

刚刚又添加了三行代码:
CString str;
pMenu->GetMenuString(0,str,MF_BYPOSITION);
AfxMessageBox(str);
弹出的MessageBox是&File,证明pMenu指向的菜单的第0位确实是File菜单没错。
现在愈发不解了。

Top

10 楼codewarrior(会思考的草)回复于 2003-11-27 11:55:16 得分 0

会不会在OnInitDialog退出的时候,光Detach一个Menu没用?要全部Detach?试试看。Top

11 楼orbit(走了走了)回复于 2003-11-27 12:54:39 得分 0

用一个类成员保存菜单,用的时候直接操作不是更好吗?Top

12 楼isdong(有些事情应该忘记)回复于 2003-11-27 16:33:18 得分 0

这类固定的菜单写到资源文件里面比较好,根本没有这类奇怪的问题

我最后的分析是一定要分离菜单句柄
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: