Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga / Notatka
Następująca uwaga techniczna nie została zaktualizowana, ponieważ została po raz pierwszy uwzględniona w dokumentacji online. W związku z tym niektóre procedury i tematy mogą być nieaktualne lub nieprawidłowe. Aby uzyskać najnowsze informacje, zaleca się wyszukanie interesującego tematu w indeksie dokumentacji online.
W tej notatce opisano architekturę routingu poleceń i wysyłania, a także zaawansowane tematy ogólne routingu komunikatów okien.
Zapoznaj się z językiem Visual C++, aby uzyskać ogólne informacje na temat architektur opisanych tutaj, szczególnie różnice między komunikatami systemu Windows, powiadomieniami sterowania i poleceniami. W tej notatce założono, że bardzo dobrze znasz problemy opisane w drukowanej dokumentacji i zajmujesz się tylko bardzo zaawansowanymi tematami.
Funkcjonalność routingu poleceń i dyspozycji MFC 1.0 ewoluuje do architektury MFC 2.0.
System Windows ma komunikat WM_COMMAND, który jest przeciążony w celu dostarczania powiadomień o poleceniach menu, akceleratora i powiadomieniach sterowania oknami dialogowymi.
MFC 1.0 nieco to rozwija, pozwalając obsłudze poleceń (na przykład "OnFileNew") w klasie pochodnej CWnd zostać wywołanej w odpowiedzi na konkretny WM_COMMAND. Jest to połączone ze strukturą danych nazywaną mapą komunikatów, co skutkuje bardzo efektywnym mechanizmem poleceń.
MFC 1.0 udostępniał również dodatkowe funkcje oddzielania powiadomień sterujących od komunikatów poleceń. Polecenia są reprezentowane przez 16-bitowy identyfikator, czasami znany jako identyfikator polecenia. Polecenia zwykle zaczynają się od CFrameWnd (czyli wyboru menu lub przetłumaczonego akceleratora) i są kierowane do różnych okien.
Usługa MFC 1.0 używała routingu poleceń w ograniczonym sensie do implementacji interfejsu wielu dokumentów (MDI). (Okno ramki MDI deleguje polecenia do aktywnego okna podrzędnego MDI).
Ta funkcja została uogólniona i rozszerzona w MFC 2.0, aby umożliwić obsługę poleceń przez szerszy zakres obiektów (nie tylko obiektów okien). Zapewnia bardziej formalną i rozszerzalną architekturę do routingu komunikatów i ponownie używa routingu docelowego poleceń, aby nie tylko obsługiwać polecenia, ale także aktualizować obiekty interfejsu użytkownika (takie jak elementy menu i przyciski paska narzędzi), aby odzwierciedlić bieżącą dostępność polecenia.
Identyfikatory poleceń
Aby zapoznać się z opisem routingu poleceń i procesu powiązania, zobacz Visual C++. Uwaga techniczna 20 zawiera informacje dotyczące nazewnictwa identyfikatorów.
Używamy ogólnego prefiksu "ID_" dla identyfikatorów poleceń. Identyfikatory poleceń wynoszą >= 0x8000. Wiersz komunikatu lub pasek stanu pokaże ciąg opisu polecenia, jeśli istnieje zasób STRINGTABLE z tymi samymi identyfikatorami co identyfikator polecenia.
W zasobach aplikacji identyfikator polecenia może pojawić się w kilku miejscach:
W jednym zasobie STRINGTABLE, który ma ten sam identyfikator co monit w wierszu komunikatu.
Prawdopodobnie w wielu zasobach MENU związanych z elementami menu wywołującymi to samo polecenie.
(ZAAWANSOWANE) w przycisku dialogowym dla polecenia GOSUB.
W kodzie źródłowym aplikacji identyfikator polecenia może pojawić się w kilku miejscach:
W pliku RESOURCE.H (lub innym głównym pliku nagłówkowym symboli) zdefiniuj identyfikatory poleceń specyficznych dla aplikacji.
W tablicy identyfikatorów używanej do utworzenia paska narzędzi, być może.
W makrze ON_COMMAND.
Być może w makrze ON_UPDATE_COMMAND_UI.
Obecnie jedyną implementacją w MFC, która wymaga identyfikatorów poleceń musi być >= 0x8000 jest implementacja okien dialogowych/poleceń GOSUB.
Polecenia GOSUB korzystające z architektury poleceń w oknach dialogowych
Architektura komend routingu i aktywacji dobrze współpracuje z oknami ramkowymi, elementami menu, przyciskami paska narzędzi, przyciskami paska dialogowego, innymi paskami sterującymi i innymi elementami interfejsu użytkownika, zaprojektowanymi do aktualizowania na żądanie oraz kierowania komend lub identyfikatorów sterowania do głównego celu komend (zazwyczaj głównego okna ramki). Główny obiekt docelowy polecenia może stosownie kierować powiadomienia o poleceniach lub kontroli do innych obiektów docelowych poleceń.
Okno dialogowe (modalne lub niemodalne) może korzystać z niektórych funkcji architektury poleceń, jeśli przydzielisz identyfikator kontrolki okna dialogowego odpowiedniemu identyfikatorowi polecenia. Obsługa okien dialogowych nie jest automatyczna, więc może być konieczne napisanie dodatkowego kodu.
Należy pamiętać, że aby wszystkie te funkcje działały prawidłowo, identyfikatory poleceń powinny mieć >wartość = 0x8000. Ponieważ wiele okien dialogowych może być kierowanych do tej samej ramki, współużytkowane polecenia powinny być >= 0x8000, podczas gdy niewspółużytkowane identyfikatory IDC w określonym oknie dialogowym powinny być <= 0x7FFF.
Można umieścić normalny przycisk w normalnym oknie dialogowym modalnym z identyfikatorem IDC przycisku ustawionym na odpowiedni identyfikator polecenia. Gdy użytkownik wybierze przycisk, właściciel okna dialogowego (zazwyczaj główne okno ramki) pobiera polecenie tak samo jak każde inne polecenie. Jest to nazywane poleceniem GOSUB, ponieważ zwykle służy do uruchamiania innego okna dialogowego (GOSUB pierwszego okna dialogowego).
Możesz również wywołać funkcję CWnd::UpdateDialogControls w oknie dialogowym i przekazać jej adres głównego okna ramki. Ta funkcja włącza lub wyłącza kontrolki okna dialogowego na podstawie tego, czy w ramce znajdują się handlery poleceń. Ta funkcja jest wywoływana automatycznie dla pasków sterowania w pętli bezczynności aplikacji, ale należy wywołać ją bezpośrednio dla normalnych okien dialogowych, które mają korzystać z tej funkcji.
W momencie wywołania ON_UPDATE_COMMAND_UI
Utrzymywanie stanu włączonego lub zaznaczonego wszystkich elementów menu programu przez cały czas może być obciążające obliczeniowo. Typową techniką jest włączenie/sprawdzenie elementów menu tylko wtedy, gdy użytkownik wybierze popUP. Implementacja CFrameWnd MFC 2.0 obsługuje komunikat WM_INITMENUPOPUP i używa architektury routingu poleceń do określania stanów menu za pośrednictwem programów obsługi ON_UPDATE_COMMAND_UI.
CFrameWnd Obsługuje również komunikat WM_ENTERIDLE opisujący bieżący element menu wybrany na pasku stanu (nazywany również wierszem komunikatu).
Struktura menu aplikacji, edytowana w Visual C++, służy do reprezentowania potencjalnych poleceń dostępnych w czasie WM_INITMENUPOPUP. Procedury obsługi ON_UPDATE_COMMAND_UI mogą modyfikować stan lub tekst menu albo, w przypadku zastosowań zaawansowanych (takich jak lista plików MRU lub czasowniki OLE w menu podręcznym), faktycznie zmodyfikować strukturę menu przed jego wyświetleniem.
To samo przetwarzanie typu ON_UPDATE_COMMAND_UI jest wykonywane dla pasków narzędzi (i innych pasków sterowania), gdy aplikacja wchodzi w stan bezczynności. Aby uzyskać więcej informacji na temat pasków sterowania, zobacz Dokumentację biblioteki klas i Uwagi techniczne 31 .
Zagnieżdżone menu pop-up
Jeśli używasz struktury menu zagnieżdżonego, zauważysz, że program obsługi ON_UPDATE_COMMAND_UI dla pierwszego elementu menu w menu podręcznym jest wywoływany w dwóch różnych przypadkach.
Najpierw wywołuje się samo menu podręczne. Jest to konieczne, ponieważ wyskakujące menu nie mają identyfikatorów i używamy identyfikatora pierwszego elementu menu podręcznego, aby odwoływać się do całego menu podręcznego. W tym przypadku zmienna członkowska m_pSubMenu obiektu CCmdUI będzie różna od null i będzie wskazywać na menu podręczne.
Po drugie, jest wywoływana tuż przed rysowaniem elementów menu w menu podręcznym. W takim przypadku identyfikator odwołuje się tylko do pierwszego elementu menu, a zmienna CCmdUI obiektu będzie równa NULL.
Dzięki temu można włączyć menu podręczne jako odrębne od elementów menu, ale wymaga to napisania kodu obsługującego menu. Na przykład w menu zagnieżdżonym z następującą strukturą:
File>
New>
Sheet (ID_NEW_SHEET)
Chart (ID_NEW_CHART)
Polecenia ID_NEW_SHEET i ID_NEW_CHART mogą być niezależnie włączone lub wyłączone. Menu podręczne Nowy powinno być włączone, jeśli któreś z dwóch jest włączone.
Procedura obsługi poleceń dla ID_NEW_SHEET (pierwsze polecenie w wyskakującym okienku) będzie wyglądać mniej więcej tak:
void CMyApp::OnUpdateNewSheet(CCmdUI* pCmdUI)
{
if (pCmdUI->m_pSubMenu != NULL)
{
// enable entire pop-up for "New" sheet and chart
BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;
// CCmdUI::Enable is a no-op for this case, so we
// must do what it would have done.
pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex,
MF_BYPOSITION |
(bEnable MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
return;
}
// otherwise just the New Sheet command
pCmdUI->Enable(m_bCanCreateSheet);
}
Procedura obsługi poleceń dla ID_NEW_CHART byłaby normalną procedurą obsługi poleceń aktualizacji i wyglądałaby następująco:
void CMyApp::OnUpdateNewChart(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_bCanCreateChart);
}
ON_COMMAND i ON_BN_CLICKED
Makra mapy komunikatów dla ON_COMMAND i ON_BN_CLICKED są takie same. Mechanizm routingu poleceń i sterowania powiadomieniami MFC używa tylko identyfikatora polecenia, aby zdecydować, gdzie należy kierować. Powiadomienia sterujące za pomocą kodu powiadomienia sterującego o wartości zero (BN_CLICKED) są interpretowane jako polecenia.
Uwaga / Notatka
W rzeczywistości wszystkie komunikaty powiadomień sterowania przechodzą przez łańcuch obsługi poleceń. Na przykład technicznie można napisać procedurę obsługi powiadomień sterujących dla EN_CHANGE w klasie dokumentów. Nie jest to ogólnie zalecane, ponieważ praktyczne zastosowania tej funkcji są nieliczne, funkcja nie jest obsługiwana przez klasę ClassWizard, a użycie tej funkcji może spowodować niestabilny kod.
Wyłączanie automatycznego wyłączania kontrolek przycisków
Jeśli umieścisz kontrolkę przycisku na pasku okna dialogowego lub w oknie dialogowym, w którym wywołujesz CWnd::UpdateDialogControls samodzielnie, zauważysz, że przyciski, które nie mają obsługi ON_COMMAND lub ON_UPDATE_COMMAND_UI, zostaną automatycznie wyłączone przez framework. W niektórych przypadkach nie będziesz potrzebował programu obsługującego, ale będziesz chciał, aby przycisk pozostał aktywny. Najprostszym sposobem osiągnięcia tego celu jest dodanie fikcyjnej procedury obsługi poleceń (łatwe do zrobienia za pomocą ClassWizard) i nic w niej nie robić.
Trasowanie komunikatów okna
Poniżej opisano bardziej zaawansowane tematy dotyczące klas MFC oraz sposób ich wpływu na routing komunikatów systemu Windows i inne tematy. Informacje przedstawione w tym miejscu zostały opisane tylko krótko. Aby uzyskać szczegółowe informacje na temat publicznych interfejsów API, zapoznaj się z dokumentacją biblioteki klas . Aby uzyskać więcej informacji na temat szczegółów implementacji, zapoznaj się z kodem źródłowym biblioteki MFC.
Aby uzyskać szczegółowe informacje na temat oczyszczania okien, proszę odnieść się do Noty technicznej 17, bardzo ważnego tematu dla wszystkich klas pochodnych CWnd.
Problemy z CWnd
Funkcja składowa implementacji CWnd::OnChildNotify zapewnia zaawansowaną i rozszerzalną architekturę dla okien podrzędnych (nazywanych również kontrolkami) w celu zaczepienia lub w inny sposób informowania o komunikatach, poleceniach i powiadomieniach sterujących, które przechodzą do elementu nadrzędnego (lub "właściciela"). Jeśli okno podrzędne (/kontrolka) jest obiektem CWnd w C++, funkcja wirtualna OnChildNotify jest wywoływana jako pierwsza z parametrami oryginalnego komunikatu (czyli strukturą MSG). Zasobnik może pozostawić wiadomość bez zmian, zignorować ją lub zmodyfikować wiadomość dla rodzica (rzadko).
Domyślna implementacja CWnd obsługuje następujące komunikaty i używa haka OnChildNotify, aby umożliwić oknom podrzędnym (kontrolkom) pierwszy dostęp do komunikatu.
WM_MEASUREITEM i WM_DRAWITEM (do samodzielnego rysowania)
WM_COMPAREITEM i WM_DELETEITEM (rysowanie własne)
WM_HSCROLL i WM_VSCROLL
WM_CTLCOLOR
WM_PARENTNOTIFY
Zauważysz, że hak OnChildNotify jest używany do zmieniania komunikatów rysowania właściciela na komunikaty rysowania samodzielnego.
Oprócz punktu zaczepienia OnChildNotify, komunikaty przewijania mają dodatkowe zachowania związane z trasowaniem. Proszę zapoznać się z informacjami poniżej, aby uzyskać więcej szczegółów na temat pasków przewijania i pochodzenia komunikatów WM_HSCROLL oraz WM_VSCROLL.
Problemy cFrameWnd
Klasa CFrameWnd zapewnia większość implementacji routingu poleceń i aktualizacji interfejsu użytkownika. Jest to używane głównie w głównym oknie ramowym aplikacji (CWinApp::m_pMainWnd), ale dotyczy wszystkich okien ramowych.
Główne okno ramki to okno z paskiem menu i jest elementem nadrzędnym paska stanu lub wiersza komunikatu. Proszę odnieść się do powyższego omówienia routingu poleceń i WM_INITMENUPOPUP.
Klasa CFrameWnd zapewnia zarządzanie aktywnym widokiem. Następujące komunikaty są kierowane przez aktywny widok:
Wszystkie komunikaty poleceń (aktywny widok uzyskuje do nich pierwszy dostęp).
WM_HSCROLL i WM_VSCROLL komunikaty z pasków przewijania siostrzanych (zobacz poniżej).
WM_ACTIVATE (i WM_MDIACTIVATE dla MDI) są przekształcane w wywołania funkcji wirtualnej CView::OnActivateView.
CmDIFrameWnd/CMDIChildWnd — problemy
Obie klasy okien ramek MDI pochodzą z CFrameWnd i dlatego są włączone dla tego samego rodzaju routingu poleceń i aktualizacji interfejsu użytkownika udostępnionego w CFrameWnd. W typowej aplikacji MDI tylko główne okno ramki (czyli obiekt CMDIFrameWnd ) przechowuje pasek menu i pasek stanu, a zatem jest głównym źródłem implementacji routingu poleceń.
Ogólny schemat routingu polega na tym, że aktywne okno podrzędne MDI uzyskuje pierwszy dostęp do poleceń. Domyślne funkcje PreTranslateMessage obsługują tabele przyspieszające zarówno dla okien podrzędnych MDI (najpierw), jak i ramki MDI (następnie), a także standardowe przyspieszenia poleceń systemowych MDI, zwykle obsługiwane przez TranslateMDISysAccel (na końcu).
Problemy z paskiem przewijania
Podczas obsługi komunikatu przewijania (WM_HSCROLL/OnHScroll i/lub WM_VSCROLL/OnVScroll) należy spróbować napisać kod obsługi, aby nie polegał na tym, skąd pochodzi komunikat paska przewijania. Jest to nie tylko ogólny problem z systemem Windows, ponieważ komunikaty przewijania mogą pochodzić z prawdziwych kontrolek paska przewijania lub z pasków przewijania WS_HSCROLL/WS_VSCROLL, które nie są kontrolkami paska przewijania.
MFC rozszerza to, aby umożliwić kontrolkom paska przewijania bycie elementami podrzędnymi lub równorzędnymi okna, które jest przewijane (w rzeczywistości relacja nadrzędna/podrzędna między paskiem przewijania a oknem może być dowolna). Jest to szczególnie ważne w przypadku wspólnych pasków przewijania z oknami dzielonymi. Szczegółowe informacje na temat implementacji CSplitterWnd można znaleźć w notatce technicznej 29, w tym więcej informacji na temat problemów z udostępnionym paskiem przewijania.
Na marginesie, istnieją dwie klasy pochodne CWnd, w których style paska przewijania określone w czasie tworzenia są zablokowane i nie są przekazywane do systemu Windows. Po przekazaniu do procedury tworzenia WS_HSCROLL i WS_VSCROLL można ustawić niezależnie, ale po utworzeniu nie można zmienić. Oczywiście nie należy bezpośrednio testować ani ustawiać bitów stylu WS_SCROLL utworzonego okna.
W przypadku CMDIFrameWnd style paska przewijania, które przekazujesz do Create lub LoadFrame, są używane do tworzenia MDICLIENT. Jeśli chcesz mieć przewijany obszar MDICLIENT (na przykład Menedżer programów systemu Windows) należy ustawić oba style paska przewijania (WS_HSCROLL | WS_VSCROLL) dla stylu użytego do utworzenia CMDIFrameWnd.
W przypadku CSplitterWnd style pasków przewijania odnoszą się do specjalnych, wspólnie używanych pasków przewijania dla regionów podziału. W przypadku okien rozdzielanych statycznie zwykle nie można ustawić stylu paska przewijania. W przypadku dynamicznych okien rozdzielających zazwyczaj będzie ustawiony styl paska przewijania dla kierunku podziału, czyli WS_HSCROLL , jeśli można podzielić wiersze, WS_VSCROLL , jeśli można podzielić kolumny.
Zobacz także
Uwagi techniczne według numeru
Uwagi techniczne według kategorii