私は同じ必要性を見つけました。 .rcファイルにメニューを定義してあり、そのサブアイテムがすべてグレー表示になっている場合は、ポップアップメニューへのアクセスをグレーアウトしたい。 (これは発見を阻害すると主張することができますが、この特定のケースでは、私たちが必要とするものです)。
前述のレスポンダのように、メニューをプログラムで作成する場合は、アイテムの親メニューハンドルを付随情報として保存することができます。
POPUPキーワードを使用してリソースファイルで定義されたメニューの場合、IDをPOPUPに関連付けることはできず、メニューツリーをプログラム上で簡単に登ることはできません。メニュー項目を再帰的に検索し、両親を追跡する必要があります。
私はこれを行うために次のコードを書いています。 EnableSubmenuItemはEnableMenuItemのように動作し、メニュー項目をIDで有効または無効にします。次に、アイテムの親メニューをチェックします。親メニューのすべての項目が無効になっている場合、親は無効になります。逆にいずれかのサブアイテムが有効になっている場合、親は有効になります。
(元の質問、メニュー項目の親hMenuの検索方法は、次のコードのルーチンFindParentMenuで対応しています)。
////////////////////////////////////////////////////////////////////////////////
// MenuContainsID - return TRUE if menu hMenu contains an item with specified ID
////////////////////////////////////////////////////////////////////////////////
static BOOL MenuContainsID (HMENU hMenu, UINT id)
{
int pos; // use signed int so we can count down and detect passing 0
MENUITEMINFO mf;
ZeroMemory(&mf, sizeof(mf)); // request just item ID
mf.cbSize = sizeof(mf);
mf.fMask = MIIM_ID;
for (pos = GetMenuItemCount(hMenu); --pos >= 0;) // enumerate menu items
if (GetMenuItemInfo(hMenu, (UINT) pos, TRUE, &mf)) // if we find the ID we are looking for return TRUE
if (mf.wID == id)
return TRUE;
return FALSE;
}
////////////////////////////////////////////////////////////////////////////////
// MenuItemIsSubmenu - returns TRUE if item # pos (position) of menu hMenu is a
// submenu. Sets phSubMenu to menu handle if so
////////////////////////////////////////////////////////////////////////////////
static BOOL MenuItemIsSubmenu (HMENU hMenu, UINT pos, HMENU *phSubMenu)
{
MENUITEMINFO mf;
ZeroMemory(&mf, sizeof(mf)); // request just submenu handle
mf.cbSize = sizeof(mf);
mf.fMask = MIIM_SUBMENU;
if (! GetMenuItemInfo(hMenu, pos, TRUE, &mf)) // failed to get item?
return FALSE;
*phSubMenu = mf.hSubMenu; // pass back by side effect
return (mf.hSubMenu != NULL); // it's a submenu if handle is not NULL
}
////////////////////////////////////////////////////////////////////////////////
// MenuItemIsEnabled - returns true if item # pos (position) of menu hMenu is
// enabled (that is, is not disabled or grayed)
////////////////////////////////////////////////////////////////////////////////
static BOOL MenuItemIsEnabled (HMENU hMenu, UINT pos)
{
return ! (GetMenuState(hMenu, pos, MF_BYPOSITION) & (MF_GRAYED | MF_DISABLED));
}
////////////////////////////////////////////////////////////////////////////////
// FindParentMenu - returns handle of the submenu of menu bar hMenu that contains
// an item with id "id". Position of this submenu is passed by side effect to
// pParentPos, and /its/ parent menu is passed by side effect through phGrandparentMenu.
////////////////////////////////////////////////////////////////////////////////
static HMENU FindParentMenu (HMENU hMenu, UINT id, HMENU *phGrandparentMenu, UINT *pparentPos)
{
int pos; // use signed int so we can count down and detect passing 0
HMENU hSubMenu, hx;
for (pos = GetMenuItemCount(hMenu); --pos >= 0;) {
if (MenuItemIsSubmenu(hMenu, (UINT) pos, &hSubMenu)) {
if (MenuContainsID(hSubMenu, id)) {
*phGrandparentMenu = hMenu; // set grandparent info by side effect
*pparentPos = (UINT) pos;
return hSubMenu; // we found the item directly
}
if ((hx = FindParentMenu(hSubMenu, id, phGrandparentMenu, pparentPos)) != NULL)
return hx; // we found the item recursively (in a sub-sub menu). It set grandparent info
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
// AllSubitemsAreDisabled - returns TRUE if all items in a submenu are disabled
////////////////////////////////////////////////////////////////////////////////
static BOOL AllSubitemsAreDisabled (HMENU hMenu)
{
int pos; // use signed int so we can count down and detect passing 0
for (pos = GetMenuItemCount(hMenu); --pos >= 0;)
if (MenuItemIsEnabled(hMenu, (UINT) pos))
return FALSE; // finding one enabled item is enough to stop
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
// EnableSubMenuItem - like EnableMenuItem, enables or disables a menu item
// by ID (only; not position!) where hMenu is top level menu.
// Added bonus: If the item is in a pop-up menu, and all items in the popup are
// now disabled, we disable the popup menu itself.
//
// Example:
// EnableSubMenuItem(hMainMenu, IDM_CONFIGURE, MF_GRAYED);
//
////////////////////////////////////////////////////////////////////////////////
void EnableSubMenuItem (HMENU hMenu, UINT id, UINT enable)
{
HMENU hParentMenu, hGrandparentMenu;
UINT parentPos;
// EnableMenuItem does its job recursively and takes care of the item
EnableMenuItem(hMenu, id, enable | MF_BYPOSITION);
// But popup menus don't have IDs so we have find the parent popup menu, and its parent (the
// grandparent menu), so we can enable or disable the popup entry by position
if ((hParentMenu = FindParentMenu(hMenu, id, &hGrandparentMenu, &parentPos)) != NULL)
EnableMenuItem(hGrandparentMenu, parentPos,
MF_BYPOSITION | (AllSubitemsAreDisabled(hParentMenu) ? MF_GRAYED : MF_ENABLED));
}
良いアイデア!残念なことに、私はしばしばメニューを作成するコードにアクセスできないので、多くの場合これを行うことはできません。私は、既存のソースコードにそのような変更を必要としない関数を探しています。 あなたは私が*ソースコードを変更することができるので、+ 1あなたのために良いオプションを指摘します! –
この回答を受け入れることで、賞金総額を得ることができます。残念ながら、この質問に対する賞金を設定しても、新たな洞察は得られませんでした。 : - / –