TN061: messaggi ON_NOTIFY e WM_NOTIFY
Nota
La seguente nota tecnica non è stata aggiornata da quando è stata inclusa per la prima volta nella documentazione online. Di conseguenza, alcune procedure e argomenti potrebbero essere non aggiornati o errati. Per le informazioni più recenti, è consigliabile cercare l'argomento di interesse nell'indice della documentazione online.
Questa nota tecnica fornisce informazioni di base sul nuovo messaggio di WM_NOTIFY e descrive il modo consigliato (e più comune) di gestire i messaggi WM_NOTIFY nell'applicazione MFC.
Messaggi di notifica in Windows 3.x
In Windows 3.x i controlli notificano agli elementi padre eventi quali clic del mouse, modifiche al contenuto e selezione e controllo del disegno dello sfondo inviando un messaggio all'elemento padre. Le notifiche semplici vengono inviate come messaggi speciali WM_COMMAND, con il codice di notifica (ad esempio BN_CLICKED) e l'ID di controllo compressi in wParam e l'handle del controllo in lParam. Si noti che poiché wParam e lParam sono pieni, non è possibile passare dati aggiuntivi. Questi messaggi possono essere solo semplici notifiche. Ad esempio, nella notifica di BN_CLICKED non è possibile inviare informazioni sulla posizione del cursore del mouse quando è stato fatto clic sul pulsante.
Quando i controlli in Windows 3.x devono inviare un messaggio di notifica che include dati aggiuntivi, usano un'ampia gamma di messaggi specifici, tra cui WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM e così via. Questi messaggi possono essere restituiti al controllo che li ha inviati. Per altre informazioni, vedere TN062: Reflection dei messaggi per i controlli Windows.
Messaggi di notifica in Win32
Per i controlli esistenti in Windows 3.1, l'API Win32 usa la maggior parte dei messaggi di notifica usati in Windows 3.x. Tuttavia, Win32 aggiunge anche una serie di controlli complessi sofisticati a quelli supportati in Windows 3.x. Spesso, questi controlli devono inviare dati aggiuntivi con i messaggi di notifica. Invece di aggiungere un nuovo messaggio di WM_* per ogni nuova notifica che richiede dati aggiuntivi, i progettisti dell'API Win32 hanno scelto di aggiungere un solo messaggio, WM_NOTIFY, che può passare qualsiasi quantità di dati aggiuntivi in modo standardizzato.
WM_NOTIFY messaggi contengono l'ID del controllo che invia il messaggio in wParam e un puntatore a una struttura in lParam. Questa struttura è una struttura NMHDR o una struttura più grande con una struttura NMHDR come primo membro. Si noti che poiché il membro NMHDR è il primo, un puntatore a questa struttura può essere usato come puntatore a un NMHDR o come puntatore alla struttura più grande a seconda della modalità di cast.
Nella maggior parte dei casi, il puntatore punterà a una struttura più grande e sarà necessario eseguirne il cast quando lo si usa. In poche notifiche, ad esempio le notifiche comuni (i cui nomi iniziano con NM_) e il TTN_SHOW del controllo della descrizione comando e le notifiche di TTN_POP, è una struttura NMHDR effettivamente usata.
La struttura NMHDR o il membro iniziale contiene l'handle e l'ID del controllo che invia il messaggio e il codice di notifica, ad esempio TTN_SHOW. Il formato della struttura NMHDR è illustrato di seguito:
typedef struct tagNMHDR {
HWND hwndFrom;
UINT idFrom;
UINT code;
} NMHDR;
Per un messaggio di TTN_SHOW, il membro del codice verrà impostato su TTN_SHOW.
La maggior parte delle notifiche passa un puntatore a una struttura più grande che contiene una struttura NMHDR come primo membro. Si consideri, ad esempio, la struttura utilizzata dal LVN_KEYDOWN messaggio di notifica del controllo visualizzazione elenco, che viene inviato quando viene premuto un tasto in un controllo visualizzazione elenco. Il puntatore punta a una struttura LV_KEYDOWN , definita come illustrato di seguito:
typedef struct tagLV_KEYDOWN {
NMHDR hdr;
WORD wVKey;
UINT flags;
} LV_KEYDOWN;
Si noti che poiché il membro NMHDR è il primo in questa struttura, il puntatore passato nel messaggio di notifica può essere eseguito il cast a un puntatore a un NMHDR o a un puntatore a un LV_KEYDOWN.
Notifiche comuni a tutti i nuovi controlli Windows
Alcune notifiche sono comuni a tutti i nuovi controlli Windows. Queste notifiche passano un puntatore a una struttura NMHDR .
Codice di notifica | Inviato perché |
---|---|
NM_CLICK | L'utente ha fatto clic sul pulsante sinistro del mouse nel controllo |
NM_DBLCLK | L'utente ha fatto doppio clic sul pulsante sinistro del mouse nel controllo |
NM_RCLICK | L'utente ha fatto clic con il pulsante destro del mouse nel controllo |
NM_RDBLCLK | L'utente ha fatto doppio clic con il pulsante destro del mouse nel controllo |
NM_RETURN | L'utente ha premuto il tasto INVIO mentre il controllo ha lo stato attivo per l'input |
NM_edizione Standard TFOCUS | Al controllo è stato assegnato lo stato attivo per l'input |
NM_KILLFOCUS | Il controllo ha perso lo stato attivo per l'input |
NM_OUTOFMEMORY | Il controllo non è riuscito a completare un'operazione perché non è disponibile memoria sufficiente |
ON_NOTIFY: Gestione dei messaggi WM_NOTIFY nelle applicazioni MFC
La funzione CWnd::OnNotify
gestisce i messaggi di notifica. L'implementazione predefinita controlla la mappa dei messaggi per i gestori di notifica da chiamare. In generale, non si esegue l'override OnNotify
di . Al contrario, si fornisce una funzione del gestore e si aggiunge una voce della mappa messaggi per tale gestore alla mappa messaggi della classe della finestra del proprietario.
ClassWizard, tramite la finestra delle proprietà ClassWizard, può creare la voce ON_NOTIFY message-map e fornire una funzione di gestore scheletro. Per altre informazioni sull'uso di ClassWizard per semplificare questa operazione, vedere Mapping dei messaggi alle funzioni.
La macro message-map ON_NOTIFY ha la sintassi seguente:
ON_NOTIFY(wNotifyCode, id, memberFxn)
dove i parametri sono:
wNotifyCode
Codice per il messaggio di notifica da gestire, ad esempio LVN_KEYDOWN.
id
Identificatore figlio del controllo per il quale viene inviata la notifica.
memberFxn
Funzione membro da chiamare quando viene inviata questa notifica.
La funzione membro deve essere dichiarata con il prototipo seguente:
afx_msg void memberFxn(NMHDR* pNotifyStruct, LRESULT* result);
dove i parametri sono:
pNotifyStruct
Puntatore alla struttura di notifica, come descritto nella sezione precedente.
result
Puntatore al codice del risultato che verrà impostato prima di tornare.
Esempio
Per specificare che si vuole che la funzione OnKeydownList1
membro gestisca LVN_KEYDOWN messaggi dall'ID CListCtrl
di cui è IDC_LIST1
, si userà ClassWizard per aggiungere quanto segue alla mappa dei messaggi:
ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnKeydownList1)
Nell'esempio precedente la funzione fornita da ClassWizard è:
void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
// TODO: Add your control notification handler
// code here
*pResult = 0;
}
Si noti che ClassWizard fornisce automaticamente un puntatore del tipo corretto. È possibile accedere alla struttura di notifica tramite pNMHDR o pLVKeyDow.
ON_NOTIFY_RANGE
Se è necessario elaborare lo stesso messaggio di WM_NOTIFY per un set di controlli, è possibile usare ON_NOTIFY_RANGE anziché ON_NOTIFY. Ad esempio, potresti avere un set di pulsanti per cui vuoi eseguire la stessa azione per un determinato messaggio di notifica.
Quando si utilizza ON_NOTIFY_RANGE, si specifica un intervallo contiguo di identificatori figlio per cui gestire il messaggio di notifica specificando gli identificatori figlio iniziale e finale dell'intervallo.
ClassWizard non gestisce ON_NOTIFY_RANGE; per usarlo, è necessario modificare manualmente la mappa dei messaggi.
La voce della mappa messaggi e il prototipo di funzione per ON_NOTIFY_RANGE sono i seguenti:
ON_NOTIFY_RANGE(wNotifyCode, id, idLast, memberFxn)
dove i parametri sono:
wNotifyCode
Codice per il messaggio di notifica da gestire, ad esempio LVN_KEYDOWN.
id
Primo identificatore nell'intervallo contiguo di identificatori.
idLast
Ultimo identificatore nell'intervallo contiguo di identificatori.
memberFxn
Funzione membro da chiamare quando viene inviata questa notifica.
La funzione membro deve essere dichiarata con il prototipo seguente:
afx_msg void memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
dove i parametri sono:
id
Identificatore figlio del controllo che ha inviato la notifica.
pNotifyStruct
Puntatore alla struttura di notifica, come descritto in precedenza.
result
Puntatore al codice del risultato che verrà impostato prima di tornare.
ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE
Se si desidera che più oggetti nel routing delle notifiche gestisca un messaggio, è possibile usare ON_NOTIFY_EX (o ON_NOTIFY_EX_RANGE) anziché ON_NOTIFY (o ON_NOTIFY_RANGE). L'unica differenza tra la versione EX e la versione normale è che la funzione membro chiamata per la versione EX restituisce un valore BOOL che indica se l'elaborazione dei messaggi deve continuare o meno. La restituzione di FAL edizione Standard da questa funzione consente di elaborare lo stesso messaggio in più oggetti.
ClassWizard non gestisce ON_NOTIFY_EX o ON_NOTIFY_EX_RANGE; se si vuole usarli, è necessario modificare manualmente la mappa dei messaggi.
Di seguito sono riportate le voci della mappa messaggi e il prototipo di funzione per ON_NOTIFY_EX e ON_NOTIFY_EX_RANGE. I significati dei parametri sono gli stessi delle versioni non EX .
ON_NOTIFY_EX(nCode, id, memberFxn)
ON_NOTIFY_EX_RANGE(wNotifyCode, id, idLast, memberFxn)
Il prototipo per entrambi gli elementi precedenti è lo stesso:
afx_msg BOOL memberFxn(UINT id, NMHDR* pNotifyStruct, LRESULT* result);
In entrambi i casi, ID contiene l'identificatore figlio del controllo che ha inviato la notifica.
La funzione deve restituire TRUE se il messaggio di notifica è stato completamente gestito o FAL edizione Standard se altri oggetti nel routing dei comandi devono avere la possibilità di gestire il messaggio.