TN061: komunikaty ON_NOTIFY i WM_NOTIFY

Uwaga

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.

Ta uwaga techniczna zawiera podstawowe informacje na temat nowego komunikatu WM_NOTIFY i opisuje zalecany (i najbardziej typowy) sposób obsługi komunikatów WM_NOTIFY w aplikacji MFC.

Komunikaty powiadomień w systemie Windows 3.x

W systemie Windows 3.x kontrolki powiadamiają rodziców o zdarzeniach, takich jak kliknięcia myszą, zmiany w zawartości i zaznaczeniu oraz sterowanie obrazem tła przez wysłanie komunikatu do elementu nadrzędnego. Proste powiadomienia są wysyłane jako specjalne komunikaty WM_COMMAND z kodem powiadomienia (takim jak BN_CLICKED) i identyfikatorem kontrolki zapakowanymi wparam i uchwytem kontrolki w lParam. Należy pamiętać, że ponieważ funkcje wParam i lParam są pełne, nie ma możliwości przekazywania żadnych dodatkowych danych — te komunikaty mogą być tylko prostymi powiadomieniami. Na przykład w powiadomieniu BN_CLICKED nie ma możliwości wysyłania informacji o lokalizacji kursora myszy po kliknięciu przycisku.

Gdy kontrolki w systemie Windows 3.x muszą wysyłać komunikat z powiadomieniem zawierający dodatkowe dane, używają różnych komunikatów specjalnego przeznaczenia, w tym WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM itd. Te komunikaty można odzwierciedlić z powrotem do kontrolki, która je wysłała. Aby uzyskać więcej informacji, zobacz TN062: Message Emocje ion for Windows Controls (TN062: Emocje komunikatów dla kontrolek systemu Windows).

Komunikaty powiadomień w systemie Win32

W przypadku kontrolek, które istniały w systemie Windows 3.1, interfejs API Win32 używa większości komunikatów powiadomień używanych w systemie Windows 3.x. Jednak Win32 dodaje również szereg zaawansowanych, złożonych kontrolek do tych obsługiwanych w systemie Windows 3.x. Często te kontrolki muszą wysyłać dodatkowe dane za pomocą komunikatów powiadomień. Zamiast dodawać nowy komunikat WM_* dla każdego nowego powiadomienia, które wymaga dodatkowych danych, projektanci interfejsu API Win32 zdecydowali się dodać tylko jeden komunikat, WM_NOTIFY, który może przekazać dowolną ilość dodatkowych danych w ustandaryzowany sposób.

WM_NOTIFY komunikaty zawierają identyfikator kontrolki wysyłającej komunikat wparam i wskaźnik do struktury w lParam. Ta struktura jest strukturą NMHDR lub większą strukturą, która ma strukturę NMHDR jako jej pierwszy element członkowski. Należy pamiętać, że ponieważ element członkowski NMHDR jest pierwszy, wskaźnik do tej struktury może być używany jako wskaźnik do nmHDR lub jako wskaźnik do większej struktury w zależności od sposobu rzutowania.

W większości przypadków wskaźnik będzie wskazywać większą strukturę i należy go rzutować podczas korzystania z niego. W kilku powiadomieniach, takich jak typowe powiadomienia (których nazwy zaczynają się od NM_) i TTN_SHOW kontrolki porad narzędzi i powiadomienia TTN_POP, jest faktycznie używana struktura NMHDR .

Struktura NMHDR lub początkowy element członkowski zawiera uchwyt i identyfikator kontrolki wysyłającej komunikat i kod powiadomienia (na przykład TTN_SHOW). Poniżej przedstawiono format struktury NMHDR :

typedef struct tagNMHDR {
    HWND hwndFrom;
    UINT idFrom;
    UINT code;
} NMHDR;

W przypadku komunikatu TTN_SHOW element członkowski kodu zostanie ustawiony na TTN_SHOW.

Większość powiadomień przekazuje wskaźnik do większej struktury zawierającej strukturę NMHDR jako jej pierwszy element członkowski. Rozważmy na przykład strukturę używaną przez LVN_KEYDOWN komunikat powiadomienia kontrolki widoku listy, który jest wysyłany po naciśnięciu klawisza w kontrolce widoku listy. Wskaźnik wskazuje strukturę LV_KEYDOWN , która jest zdefiniowana, jak pokazano poniżej:

typedef struct tagLV_KEYDOWN {
    NMHDR hdr;
    WORD wVKey;
    UINT flags;
} LV_KEYDOWN;

Należy pamiętać, że ponieważ element członkowski NMHDR jest pierwszy w tej strukturze, wskaźnik przekazywany w komunikacie powiadomienia można rzutować do wskaźnika do nmHDR lub wskaźnika do LV_KEYDOWN.

Powiadomienia wspólne dla wszystkich nowych kontrolek systemu Windows

Niektóre powiadomienia są wspólne dla wszystkich nowych kontrolek systemu Windows. Te powiadomienia przekazują wskaźnik do struktury NMHDR .

Kod powiadomienia Wysłane z powodu
NM_CLICK Użytkownik kliknął lewy przycisk myszy w kontrolce
NM_DBLCLK Użytkownik dwukrotnie kliknął lewy przycisk myszy w kontrolce
NM_RCLICK Użytkownik kliknął prawym przyciskiem myszy w kontrolce
NM_RDBLCLK Użytkownik dwukrotnie kliknął prawym przyciskiem myszy w kontrolce
NM_RETURN Użytkownik nacisnął klawisz ENTER, gdy kontrolka ma fokus wejściowy
NM_SETFOCUS Kontrolka została nadana fokusowi danych wejściowych
NM_KILLFOCUS Kontrolka straciła fokus wejściowy
NM_OUTOFMEMORY Kontrola nie mogła ukończyć operacji, ponieważ nie było wystarczającej ilości dostępnej pamięci

ON_NOTIFY: obsługa komunikatów WM_NOTIFY w aplikacjach MFC

Funkcja CWnd::OnNotify obsługuje komunikaty powiadomień. Jego domyślna implementacja sprawdza mapę komunikatów, aby programy obsługi powiadomień wywoływać. Ogólnie rzecz biorąc, nie zastępujesz OnNotifyelementu . Zamiast tego należy podać funkcję obsługi i dodać wpis message-map dla tej procedury obsługi do mapy komunikatów klasy okna właściciela.

KlasaWizard, za pośrednictwem arkusza właściwości ClassWizard, może utworzyć wpis ON_NOTIFY message-map i zapewnić szkielet funkcji obsługi. Aby uzyskać więcej informacji na temat używania klasy ClassWizard, aby ułatwić to zadanie, zobacz Mapowanie komunikatów na funkcje.

Makro ON_NOTIFY message-map ma następującą składnię:

ON_NOTIFY(wNotifyCode, id, memberFxn)

gdzie parametrami są:

wNotifyCode
Kod do obsłużenia komunikatu powiadomienia, na przykład LVN_KEYDOWN.

id
Identyfikator podrzędny kontrolki, dla której jest wysyłane powiadomienie.

memberFxn
Funkcja składowa, która ma być wywoływana po wysłaniu tego powiadomienia.

Funkcja składowa musi być zadeklarowana przy użyciu następującego prototypu:

afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);

gdzie parametrami są:

pNotify, struktura
Wskaźnik do struktury powiadomień zgodnie z opisem w powyższej sekcji.

Wynik
Wskaźnik do kodu wynikowego, który zostanie ustawiony przed zwróceniem.

Przykład

Aby określić, że funkcja OnKeydownList1 składowa ma obsługiwać komunikaty LVN_KEYDOWN z identyfikatora CListCtrlIDC_LIST1, należy użyć klasy ClassWizard, aby dodać następujące elementy do mapy komunikatów:

ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)

W powyższym przykładzie funkcja udostępniana przez klasę ClassWizard to:

void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
    LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;

    // TODO: Add your control notification handler
    //       code here

    *pResult = 0;
}

Należy pamiętać, że klasa ClassWizard zapewnia wskaźnik odpowiedniego typu automatycznie. Dostęp do struktury powiadomień można uzyskać za pomocą ciągu pNMHDR lub pLVKeyDow.

ON_NOTIFY_RANGE

Jeśli musisz przetworzyć ten sam komunikat WM_NOTIFY dla zestawu kontrolek, możesz użyć ON_NOTIFY_RANGE, a nie ON_NOTIFY. Na przykład może istnieć zestaw przycisków, dla których chcesz wykonać tę samą akcję dla określonego komunikatu powiadomienia.

W przypadku używania ON_NOTIFY_RANGE należy określić ciągły zakres identyfikatorów podrzędnych, dla których ma być obsługiwany komunikat powiadomienia, określając początkowy i kończący identyfikatory podrzędne zakresu.

KlasaWizard nie obsługuje ON_NOTIFY_RANGE; aby go użyć, musisz samodzielnie edytować mapę wiadomości.

Pozycja i prototyp funkcji mapy komunikatów dla ON_NOTIFY_RANGE są następujące:

ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)

gdzie parametrami są:

wNotifyCode
Kod do obsłużenia komunikatu powiadomienia, na przykład LVN_KEYDOWN.

id
Pierwszy identyfikator w ciągłym zakresie identyfikatorów.

idLast
Ostatni identyfikator w ciągłym zakresie identyfikatorów.

memberFxn
Funkcja składowa, która ma być wywoływana po wysłaniu tego powiadomienia.

Funkcja składowa musi być zadeklarowana przy użyciu następującego prototypu:

afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

gdzie parametrami są:

id
Identyfikator podrzędny kontrolki, która wysłała powiadomienie.

pNotify, struktura
Wskaźnik do struktury powiadomień, zgodnie z powyższym opisem.

Wynik
Wskaźnik do kodu wynikowego, który zostanie ustawiony przed zwróceniem.

ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE

Jeśli chcesz, aby w routingu powiadomień obsługiwał komunikat więcej niż jeden obiekt, możesz użyć ON_NOTIFY_EX (lub ON_NOTIFY_EX_RANGE), a nie ON_NOTIFY (lub ON_NOTIFY_RANGE). Jedyną różnicą między wersją EX a zwykłą wersją jest to, że funkcja składowa wywoływana dla wersji EX zwraca wartość LOGICZNĄ wskazującą, czy przetwarzanie komunikatów powinno być kontynuowane. Zwracanie wartości FALSE z tej funkcji umożliwia przetworzenie tego samego komunikatu w więcej niż jednym obiekcie.

Klasa ClassWizard nie obsługuje ON_NOTIFY_EX ani ON_NOTIFY_EX_RANGE; Jeśli chcesz użyć jednej z nich, musisz samodzielnie edytować mapę wiadomości.

Kod wejściowy i prototyp funkcji mapy komunikatów dla ON_NOTIFY_EX i ON_NOTIFY_EX_RANGE są następujące. Znaczenia parametrów są takie same jak w przypadku wersji innych niż EX .

ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)

Prototyp dla obu powyższych elementów jest taki sam:

afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);

W obu przypadkach identyfikator przechowuje identyfikator podrzędny kontrolki, która wysłała powiadomienie.

Funkcja musi zwrócić wartość TRUE , jeśli komunikat powiadomienia został całkowicie obsłużony lub FAŁSZ , jeśli inne obiekty w routingu poleceń powinny mieć możliwość obsługi komunikatu.

Zobacz też

Uwagi techniczne według numerów
Uwagi techniczne według kategorii