为什么我不能禁用/灰掉菜单项?(MFC)

8
我正在尝试使用 CMenu::EnableMenuItem() 方法禁用/灰掉菜单项。
我有一个 CMenu* 变量 pMenu 引用对话框的顶部菜单。我可以使用 pMenu->GetSubMenu(int) 获取子菜单,并使用 submenu->GetMenuStringA() 验证返回的子菜单/菜单项的名称。但是,我在EnableMenuItem()方法上遇到了问题。假设有一个File 菜单,其中包含NewOpen弹出菜单以及ImportCloseClose All菜单项。NewOpen 有子菜单项(例如 New-> Document )。使用submenu->EnableMenuItem([submenu/menuitem的位置], MF_BYPOSITION | MF_GRAYED); 我可以禁用 NewOpen,但是对于ImportCloseClose All以及所有带有 New和Open 的菜单项,该函数均失败。
注意:当我说 EnableMenuItem() 失败时,我的意思并不是它会返回 -1。它返回之前的状态,但菜单不会变为禁用或灰掉。
在 MSDN 的EnableMenuItem()文档中:http://msdn.microsoft.com/en-us/library/h62wh3y1.aspx它声称这将适用于弹出式和标准菜单项。然而,它似乎仅适用于弹出式菜单项。
2个回答

7

问题是,我正在使用外部应用程序完成所有这些操作。我正在使用主窗口的句柄来获取其菜单,然后使用GetSubMenu来获取其子菜单,我无法访问CCmdUI对象。 - Amre
@Amre,那你就卡住了。你试图控制的应用程序通过自己的CCmdUI对象不断重置启用/禁用状态,你所做的任何更改都将在毫秒内被还原。 - Mark Ransom
我想要实现的目标是向按钮发送oncommand消息。我正在尝试创建一个应用程序,以便测试我的应用程序的安全性,防止有人发送oncommand或bn_clicked消息到控件并访问他们不应该访问的内容。 - Amre
我意识到我从未真正更新过这个。最终,我没有费心去尝试启用灰色按钮或菜单项,而是在它们被禁用时调用它们。我对这样的按钮进行了如下操作:CWnd* selCWnd = //获取 CWnd 引用 ::SendMessage(selCWnd->m_hWnd, WM_LBUTTONDOWN, 0, 0); ::SendMessage(selCWnd->m_hWnd, WM_LBUTTONUP, 0, 0); 因此,我发现我只需发送一个左键按下命令,然后是一个左键松开命令,就可以模拟点击它并且它有效! - Amre
对于菜单项,我使用PostMessage发送WM_COMMAND消息到具有相应ID的菜单项来实现。 例如:::PostMessage(m_HWNDSel,WM_COMMAND,MAKEWPARAM(id,0),0); 这里的id是菜单项ID,我通过获取引用了菜单栏的PMenu并迭代所有子菜单来获取这些ID,然后使用pMenu->GetMenuItemID()获取菜单项ID。 - Amre

3
根据ScottMcP-MVP MFC的说法,菜单配置是在ON_UPDATE_COMMAND_UI处理程序中完成的: 当应用程序的用户下拉菜单时,每个菜单项都需要知道它是否应该显示为启用或禁用。菜单命令的目标通过实现ON_UPDATE_COMMAND_UI处理程序来提供此信息。对于应用程序中的每个命令用户界面对象,请使用“属性”窗口创建消息映射条目和每个处理程序的函数原型。
当下拉菜单时,框架会搜索并调用每个ON_UPDATE_COMMAND_UI处理程序,每个处理程序调用CCmdUI成员函数(例如Enable和Check),然后框架会适当地显示每个菜单项。
这意味着您必须在自己的类中存储可以被选中/取消选中的菜单项的预期状态。您将不得不在每个菜单元素附近放置一个“ON_UPDATE_COMMAND_UI”宏,该元素将引用一个可根据需要修改CCmdUi对象的函数。但由于您正在使用MFC,通常不需要手动完成此操作,而只需使用包含菜单的窗口的属性即可。

1
我理解你的意思,但那并不是我想要做的。我不是试图通过应用程序启用/禁用项目。我是在外部应用程序中调用所有这些方法。 - Amre
2
你肯定做不到那个!相反,你应该向MFC应用程序发送自定义消息,告诉它某些菜单项应该变灰。然后在MFC应用程序内部,你就可以使用ON_UPDATE_COMMAND_UI处理程序来启用/禁用它们。我无法想象还有其他方法适用于MFC应用程序。 - Serge Ballesta
如果我知道菜单项的ID,有没有办法调用oncommand或Bn_clicked消息处理程序?我尝试使用sendmessage和postmessage传递主窗口的句柄以及BN_CLICKED和WM_COMMAND,但似乎不起作用。 - Amre
1
@Amre 你无法从应用程序外部触发那些MFC事件,因为它们是由MFC框架生成的。 - Serge Ballesta
我意识到我从未真正更新过这个。最终,我没有费心去尝试启用灰色按钮或菜单项,而是在它们被禁用时调用它们。我对像这样的按钮执行了以下操作:CWnd* selCWnd = //获取 CWnd 引用 ::SendMessage(selCWnd->m_hWnd, WM_LBUTTONDOWN, 0, 0); ::SendMessage(selCWnd->m_hWnd, WM_LBUTTONUP, 0, 0);所以我发现我只需要发送一个左键按下命令,然后是一个左键松开命令,就可以模拟点击它并且它有效! - Amre
对于菜单项,我使用PostMessage通过发送WM_COMMAND消息到具有ID的菜单项来完成。例如:::PostMessage(m_HWNDSel, WM_COMMAND, MAKEWPARAM(id, 0), 0);其中id是菜单项ID。我能够通过获取引用到引用菜单栏的PMenu来获得这些ID,然后迭代所有子菜单并使用pMenu->GetMenuItemID()获取菜单项ID。 - Amre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接