TN062: reflection messaggi per controlli Windows
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 descrive la reflection dei messaggi, una nuova funzionalità in MFC 4.0. Contiene inoltre indicazioni per la creazione di un semplice controllo riutilizzabile che usa la reflection dei messaggi.
Questa nota tecnica non illustra la reflection del messaggio perché si applica ai controlli ActiveX (in precedenza denominati controlli OLE). Vedere l'articolo Controlli ActiveX: sottoclassazione di un controllo Windows.
Che cos'è la reflection dei messaggi
I controlli Windows inviano spesso messaggi di notifica alle finestre padre. Ad esempio, molti controlli inviano un messaggio di notifica colore del controllo (WM_CTLCOLOR o una delle relative varianti) al padre per consentire all'elemento padre di fornire un pennello per disegnare lo sfondo del controllo.
In Windows e in MFC prima della versione 4.0, la finestra padre, spesso una finestra di dialogo, è responsabile della gestione di questi messaggi. Ciò significa che il codice per la gestione del messaggio deve trovarsi nella classe della finestra padre e che deve essere duplicato in ogni classe che deve gestire tale messaggio. Nel caso precedente, ogni finestra di dialogo che voleva controlli con sfondi personalizzati dovrà gestire il messaggio di notifica del colore del controllo. Sarebbe molto più facile riutilizzare il codice se fosse possibile scrivere una classe di controllo che gestirebbe il proprio colore di sfondo.
In MFC 4.0 il meccanismo precedente funziona ancora. Le finestre padre possono gestire i messaggi di notifica. Inoltre, MFC 4.0 facilita il riutilizzo fornendo una funzionalità denominata "reflection dei messaggi" che consente di gestire questi messaggi di notifica nella finestra di controllo figlio o nella finestra padre o in entrambi. Nell'esempio di colore di sfondo del controllo è ora possibile scrivere una classe di controllo che imposta il proprio colore di sfondo gestendo il messaggio WM_CTLCOLOR riflesso, tutto senza basarsi sull'elemento padre. Si noti che poiché la reflection dei messaggi è implementata da MFC, non da Windows, la classe della finestra padre deve essere derivata da CWnd
per consentire il funzionamento della reflection dei messaggi.
Le versioni precedenti di MFC hanno fatto qualcosa di simile alla reflection dei messaggi fornendo funzioni virtuali per alcuni messaggi, ad esempio messaggi per le caselle di riepilogo disegnate dal proprietario (WM_DRAWITEM e così via). Il nuovo meccanismo di reflection dei messaggi è generalizzato e coerente.
La reflection dei messaggi è compatibile con le versioni precedenti alla versione 4.0 del codice scritto per MFC.
Se è stato fornito un gestore per un messaggio specifico o per un intervallo di messaggi, nella classe della finestra padre, eseguirà l'override dei gestori di messaggi riflessi per lo stesso messaggio purché non venga chiamata la funzione del gestore della classe base nel proprio gestore. Ad esempio, se si gestisce WM_CTLCOLOR nella classe della finestra di dialogo, la gestione eseguirà l'override di eventuali gestori di messaggi riflessi.
Se, nella classe finestra padre, si fornisce un gestore per un messaggio di WM_NOTIFY specifico o un intervallo di messaggi WM_NOTIFY, il gestore verrà chiamato solo se il controllo figlio che invia tali messaggi non dispone di un gestore di messaggi riflesso tramite ON_NOTIFY_REFLECT()
. Se si usa ON_NOTIFY_REFLECT_EX()
nella mappa dei messaggi, il gestore di messaggi potrebbe o meno consentire alla finestra padre di gestire il messaggio. Se il gestore restituisce FAL edizione Standard, il messaggio verrà gestito anche dall'elemento padre, mentre una chiamata che restituisce TRUE non consente all'elemento padre di gestirlo. Si noti che il messaggio riflesso viene gestito prima del messaggio di notifica.
Quando viene inviato un messaggio di WM_NOTIFY, il controllo viene offerta la prima possibilità di gestirlo. Se viene inviato un altro messaggio riflesso, la finestra padre ha la prima possibilità di gestirlo e il controllo riceverà il messaggio riflesso. A tale scopo, sarà necessaria una funzione del gestore e una voce appropriata nella mappa messaggi della classe del controllo.
La macro della mappa messaggi per i messaggi riflessi è leggermente diversa rispetto alle notifiche regolari: ha _REFLECT aggiunto al nome consueto. Ad esempio, per gestire un messaggio di WM_NOTIFY nell'elemento padre, utilizzare la macro ON_NOTIFY nella mappa dei messaggi dell'elemento padre. Per gestire il messaggio riflesso nel controllo figlio, utilizzare la macro ON_NOTIFY_REFLECT nella mappa messaggi del controllo figlio. In alcuni casi, anche i parametri sono diversi. Si noti che ClassWizard può in genere aggiungere le voci della mappa dei messaggi e fornire implementazioni di funzione scheletro con parametri corretti.
Per informazioni sul nuovo messaggio di WM_NOTIFY, vedere TN061: ON_NOTIFY e messaggi di WM_NOTIFY.
Voci di Message-Map e prototipi di funzioni del gestore per i messaggi riflessi
Per gestire un messaggio di notifica del controllo riflesso, usare le macro e i prototipi di funzione della mappa messaggi elencati nella tabella seguente.
ClassWizard può in genere aggiungere queste voci della mappa dei messaggi per l'utente e fornire implementazioni di funzioni scheletro. Per informazioni su come definire i gestori per i messaggi riflessi, vedere Definizione di un gestore messaggi per un messaggio riflesso.
Per eseguire la conversione dal nome del messaggio al nome della macro riflessa, anteporre ON_ e accodare _REFLECT. Ad esempio, WM_CTLCOLOR diventa ON_WM_CTLCOLOR_REFLECT. Per visualizzare i messaggi che possono essere visualizzati, eseguire la conversione opposta nelle voci di macro nella tabella seguente.
Le tre eccezioni alla regola precedente sono le seguenti:
La macro per le notifiche di WM_COMMAND è ON_CONTROL_REFLECT.
La macro per le reflection WM_NOTIFY è ON_NOTIFY_REFLECT.
La macro per le reflection ON_UPDATE_COMMAND_UI è ON_UPDATE_COMMAND_UI_REFLECT.
In ognuno dei casi speciali precedenti è necessario specificare il nome della funzione membro del gestore. Negli altri casi, è necessario usare il nome standard per la funzione del gestore.
I significati dei parametri e i valori restituiti delle funzioni sono documentati sotto il nome della funzione o il nome della funzione con On anteporto. Ad esempio, CtlColor
è documentato in OnCtlColor
. Diversi gestori di messaggi riflessi richiedono meno parametri rispetto ai gestori simili in una finestra padre. È sufficiente trovare la corrispondenza con i nomi nella tabella seguente con i nomi dei parametri formali nella documentazione.
Voce della mappa | Prototipo di funzione |
---|---|
ON_CONTROL_REFLECT(wNotifyCode ,)memberFxn |
afx_msg voidmemberFxn ( ); |
ON_NOTIFY_REFLECT(wNotifyCode ,)memberFxn |
afx_msg voidmemberFxn ( NMHDR*pNotifyStruct , LRESULT*result); |
ON_UPDATE_COMMAND_UI_REFLECT(memberFxn ) |
afx_msg voidmemberFxn ( CCmdUI);*pCmdUI |
ON_WM_CTLCOLOR_REFLECT( ) | afx_msg HBRUSH CtlColor ( CDCpDC *, UINT);nCtlColor |
ON_WM_DRAWITEM_REFLECT( ) | afx_msg void DrawItem ( LPDRAWITEMSTRUCTlpDrawItemStruct ); |
ON_WM_MEASUREITEM_REFLECT( ) | afx_msg void MeasureItem ( LPMEASUREITEMSTRUCTlpMeasureItemStruct ); |
ON_WM_DELETEITEM_REFLECT( ) | afx_msg void DeleteItem ( LPDELETEITEMSTRUCTlpDeleteItemStruct ); |
ON_WM_COMPAREITEM_REFLECT( ) | afx_msg int CompareItem ( LPCOMPAREITEMSTRUCTlpCompareItemStruct ); |
ON_WM_CHARTOITEM_REFLECT( ) | afx_msg int CharToItem ( UINTnKey , UINT);nIndex |
ON_WM_VKEYTOITEM_REFLECT( ) | afx_msg int VKeyToItem ( UINTnKey , UINT);nIndex |
ON_WM_HSCROLL_REFLECT( ) | afx_msg void HScroll ( UINTnSBCode , UINT);nPos |
ON_WM_VSCROLL_REFLECT( ) | afx_msg void VScroll ( UINTnSBCode , UINT);nPos |
ON_WM_PARENTNOTIFY_REFLECT( ) | afx_msg void ParentNotify ( UINTmessage , LPARAM);lParam |
Le macro ON_NOTIFY_REFLECT e ON_CONTROL_REFLECT presentano variazioni che consentono a più oggetti ,ad esempio il controllo e il relativo padre, di gestire un determinato messaggio.
Voce della mappa | Prototipo di funzione |
---|---|
ON_NOTIFY_REFLECT_EX(wNotifyCode ,)memberFxn |
afx_msg BOOLmemberFxn ( NMHDR*pNotifyStruct , LRESULT*result); |
ON_CONTROL_REFLECT_EX(wNotifyCode ,)memberFxn |
afx_msg BOOLmemberFxn ( ); |
Gestione dei messaggi riflessi: esempio di un controllo riutilizzabile
Questo semplice esempio crea un controllo riutilizzabile denominato CYellowEdit
. Il controllo funziona come un normale controllo di modifica, ad eccezione del fatto che visualizza testo nero su uno sfondo giallo. Sarebbe facile aggiungere funzioni membro che consentono al CYellowEdit
controllo di visualizzare colori diversi.
Per provare l'esempio che crea un controllo riutilizzabile
Creare una nuova finestra di dialogo in un'applicazione esistente. Per altre informazioni, vedere l'argomento editor di dialoghi.
È necessario disporre di un'applicazione in cui sviluppare il controllo riutilizzabile. Se non si dispone di un'applicazione esistente da usare, creare un'applicazione basata su dialoghi usando AppWizard.
Con il progetto caricato in Visual C++, usare ClassWizard per creare una nuova classe denominata
CYellowEdit
basata suCEdit
.Aggiungere tre variabili membro alla
CYellowEdit
classe. Le prime due saranno variabili COLORREF per contenere il colore del testo e il colore di sfondo. Il terzo sarà unCBrush
oggetto che conterrà il pennello per disegnare lo sfondo. L'oggettoCBrush
consente di creare il pennello una volta, semplicemente facendo riferimento a esso dopo, e di distruggere automaticamente il pennello quando ilCYellowEdit
controllo viene distrutto.Inizializzare le variabili membro scrivendo il costruttore nel modo seguente:
CYellowEdit::CYellowEdit() { m_clrText = RGB(0, 0, 0); m_clrBkgnd = RGB(255, 255, 0); m_brBkgnd.CreateSolidBrush(m_clrBkgnd); }
Usando ClassWizard, aggiungere un gestore per il messaggio WM_CTLCOLOR riflesso alla
CYellowEdit
classe. Si noti che il segno di uguale davanti al nome del messaggio nell'elenco dei messaggi che è possibile gestire indica che il messaggio viene riflesso. Questo argomento è descritto in Definizione di un gestore di messaggi per un messaggio riflesso.ClassWizard aggiunge automaticamente la macro message-map e la funzione skeleton seguenti:
ON_WM_CTLCOLOR_REFLECT() // Note: other code will be in between.... HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor) { // TODO: Change any attributes of the DC here // TODO: Return a non-NULL brush if the // parent's handler should not be called return NULL; }
Sostituire il corpo della funzione con il codice seguente. Il codice specifica il colore del testo, il colore di sfondo del testo e il colore di sfondo per il resto del controllo.
pDC->SetTextColor(m_clrText); // text pDC->SetBkColor(m_clrBkgnd); // text bkgnd return m_brBkgnd; // ctl bkgnd
Creare un controllo di modifica nella finestra di dialogo, quindi collegarlo a una variabile membro facendo doppio clic sul controllo di modifica tenendo premuto un tasto di controllo. Nella finestra di dialogo Aggiungi variabile membro completare il nome della variabile e scegliere "Control" per la categoria, quindi "CYellowEdit" per il tipo di variabile. Non dimenticare di impostare l'ordine di tabulazioni nella finestra di dialogo. Assicurarsi inoltre di includere il file di intestazione per il
CYellowEdit
controllo nel file di intestazione della finestra di dialogo.Compilare ed eseguire l'applicazione. Il controllo di modifica avrà uno sfondo giallo.