Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł ułatwia rozwiązanie problemu występującego po dołączeniu menu do okna dialogowego w programie Visual C++.
Oryginalna wersja produktu: Visual C++, .NET 2002
Oryginalny numer KB: 242577
Objawy
Uwaga / Notatka
Programy Microsoft Visual C++ .NET 2002 i Visual C++ .NET 2003 obsługują zarówno model kodu zarządzanego, który jest dostarczany przez program .NET Framework, jak i niezarządzany natywny model kodu systemu Windows. Informacje zawarte w tym artykule dotyczą tylko niezarządzanych kodu Visual C++. Program Visual C++ 2005 obsługuje zarówno zarządzany model kodu udostępniany przez program .NET Framework, jak i niezarządzany natywny model kodu systemu Windows.
Zmiana stanu (włączenie/wyłączenie, zaznaczenie/odznaczenie, zmiana tekstu) elementu menu z jego procedury obsługi interfejsu użytkownika (UI) polecenia nie działa poprawnie, jeśli menu jest dołączone do okna dialogowego.
void CTestDlg::OnUpdateFileExit(CCmdUI* pCmdUI)
{
pCmdUI->Enable(FALSE); //Not calling the command handler, but does not show as disabled.
pCmdUI->SetCheck(TRUE); // Does not show check mark before the text.
pCmdUI->SetRadio(TRUE); // Does not show dot before the text.
pCmdUI->SetText("Close"); //Does not change the text.
}
Przyczyna
Gdy jest wyświetlane menu rozwijane, komunikat WM_INITMENUPOPUP jest wysyłany przed wyświetleniem elementów menu. Funkcja MFC CFrameWnd::OnInitMenuPopup przechodzi przez elementy menu i wywołuje obsługę aktualizacji interfejsu użytkownika dla elementu, jeśli taka istnieje. Wygląd każdego elementu menu jest aktualizowany w celu odzwierciedlenia jego stanu (włączone/wyłączone, zaznaczone/niezaznaczone).
Mechanizm aktualizacji interfejsu użytkownika nie działa w przypadku aplikacji opartej na oknach dialogowych, ponieważ CDialog nie ma procedury obsługi OnInitMenuPopup i używa domyślnej procedury obsługi CWnd, która nie wywołuje procedur obsługi interfejsu użytkownika poleceń aktualizacji dla elementów menu.
Rezolucja
Aby rozwiązać ten problem, wykonaj następujące czynności:
ON_WM_INITMENUPOPUPDodaj wpis do mapy komunikatów:BEGIN_MESSAGE_MAP(CTestDlg, CDialog) // }} AFX_MSG_MAP ON_WM_INITMENUPOPUP() END_MESSAGE_MAP()Dodaj funkcję składową
OnInitMenuPopupdo klasy okna dialogowego i skopiuj następujący kod:Uwaga / Notatka
Ten kod jest pobierany głównie z CFrameWnd::OnInitMenuPopup w WinFrm.cpp)
void CTestDlg::OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu)
{
// Make sure this is actually a menu. When clicking the program icon
// in the window title bar this function will trigger and pPopupMenu
// will NOT be a menu.
if (!IsMenu(pPopupMenu->m_hMenu))
return;
ASSERT(pPopupMenu != NULL);
// Check the enabled state of various menu items.
CCmdUI state;
state.m_pMenu = pPopupMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
// Determine if menu is popup in top-level menu and set m_pOther to
// it if so (m_pParentMenu == NULL indicates that it is secondary popup).
HMENU hParentMenu;
if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)
state.m_pParentMenu = pPopupMenu; // Parent == child for tracking popup.
else if ((hParentMenu = ::GetMenu(m_hWnd))!= NULL)
{
CWnd* pParent = this;
// Child windows don't have menus--need to go to the top!
if (pParent != NULL &&
(hParentMenu = ::GetMenu(pParent->m_hWnd))!= NULL)
{
int nIndexMax = ::GetMenuItemCount(hParentMenu);
for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
{
if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)
{
// When popup is found, m_pParentMenu is containing menu.
state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
break;
}
}
}
}
state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
if (state.m_nID == 0)
continue; // Menu separator or invalid cmd - ignore it.
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if (state.m_nID == (UINT)-1)
{
// Possibly a popup menu, route to first item of that popup.
state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
if (state.m_pSubMenu == NULL ||
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // First item of popup can't be routed to.
}
state.DoUpdate(this, TRUE); // Popups are never auto disabled.
}
else
{
// Normal menu item.
// Auto enable/disable if frame window has m_bAutoMenuEnable
// set and command is _not_ a system command.
state.m_pSubMenu = NULL;
state.DoUpdate(this, FALSE);
}
// Adjust for menu deletions and additions.
UINT nCount = pPopupMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}
Status
Jest to zamierzone działanie.
Więcej informacji
Obsługujący interfejs użytkownika polecenia aktualizacji jest również wywoływany z CWnd::OnCommand programu, aby upewnić się, że polecenie nie zostało wyłączone przed przekierowaniem. Dlatego program obsługi poleceń nie jest wywoływany dla wyłączonego elementu menu, mimo że nie jest on szary (niedostępny). Elementy menu nie są rysowane w celu odzwierciedlenia ich stanu w tym przypadku. Jest to powiązany kod z pliku Wincore.cpp:
// Make sure command has not become disabled before routing.
CTestCmdUI state;
state.m_nID = nID;
OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);
if (!state.m_bEnabled)
{
TRACE1("Warning: not executing disabled command %d\n", nID);
return TRUE;
}
Kroki odtwarzania zachowania
Wykonaj następujące kroki, aby odtworzyć to zachowanie w programie Visual C++ .NET:
Utwórz aplikację opartą na oknach dialogowych MFC przy użyciu aplikacji AppWizard.
Utwórz nowy zasób menu i dodaj do niego elementy menu Plik i Plik/Zakończ .
Ustaw to menu jako menu okna dialogowego w oknie dialogowym Właściwości. W tym celu otwórz zasób okna dialogowego w edytorze okien dialogowych. W oknie Właściwości kliknij Opcje Menu. Identyfikator nowego zasobu menu jest wyświetlany w rozwijanej liście edytora właściwości menu.
Dodaj obsługę
UPDATE_COMMAND_UIdla elementu menu Plik/Zakończ. W tym celu kliknij prawym przyciskiem myszy pozycję Plik/Zakończ w edytorze menu, a następnie kliknij polecenie Dodaj program obsługi zdarzeń. W kreatorze obsługi zdarzeń dodaj proceduręUPDATE_COMMAND_UIdo klasy pochodnejCDialogprojektu. Kliknij przycisk Dodaj i edytuj , aby utworzyć procedurę obsługi, a następnie dodaj jedną z tych instrukcji do wygenerowanej metody obsługi:pCmdUI->Enable(FALSE); //Not calling the handler, but does not show as disabled pCmdUI->SetCheck(TRUE); // Does not show check mark before the text. pCmdUI->SetRadio(TRUE); // Does not show dot before the text. pCmdUI->SetText("Close"); //Does not change the text.Skompiluj i uruchom aplikację.