나는 같은 필요성을 발견했다. 나는 내 메뉴를 .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을 부탁드립니다! –
이 대답을 수락하면 전체 현상금 값을 얻을 수 있습니다. 불행히도,이 질문에 대한 현상금을 설정해도 새로운 통찰력을 얻지는 못했습니다. : - / –