TN014: controlli personalizzati
In questa nota viene descritto il supporto MFC per i controlli di disegno automatico e personalizzati. Descrive anche la sottoclasse dinamica e descrive la relazione tra gli oggetti CWnd e HWND
s.
Nell'applicazione MFC di esempio CTRLTEST viene illustrato come utilizzare molti controlli personalizzati. Vedere il codice sorgente per l'esempio generale MFC CTRLTEST e la Guida online.
Menu e controlli per il disegno personalizzato
Windows fornisce il supporto per menu e controlli di disegno personalizzato utilizzando i messaggi di Windows. La finestra padre del controllo o del menu riceve questi messaggi e chiama delle funzioni in risposta. È possibile eseguire l'override di queste funzioni per personalizzare l'aspetto e il comportamento del controllo o del menu per il disegno personalizzato.
MFC supporta direttamente il disegno personalizzato con le seguenti funzioni:
È possibile eseguire l'override di queste funzioni nella classe derivata CWnd
per implementare il comportamento di disegno personalizzato.
Questo approccio non porta ad avere codice riutilizzabile. Se si dispone di due controlli simili in due differenti classi CWnd
, è necessario implementare il comportamento del controllo personalizzato in due posizioni. L'architettura del controllo di disegno automatico supportata da MFC risolve il problema.
Menu e controlli di disegno automatico
MFC fornisce un'implementazione predefinita (nelle CWnd
classi e CMenu ) per i messaggi di disegno proprietario standard. Questa implementazione predefinita decodificherà i parametri per il disegno personalizzato e delegherà i messaggi per il disegno personalizzato ai controlli o al menu. Si tratta di disegno automatico perché il codice di disegno è nella classe del controllo o del menu, non nella finestra proprietaria.
Tramite i comandi di disegno automatico è possibile compilare le classi di controlli riutilizzabili che utilizzano la semantica di disegno personalizzato per visualizzare il controllo. Il codice per disegnare il controllo è nella classe di controllo, non nel padre. Si tratta di un approccio orientato agli oggetti per la programmazione dei controlli personalizzati. Aggiungere il seguente elenco di funzioni alle classi di disegno automatico:
Per i pulsanti di disegno automatico:
CButton:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw this button
Per i menu di disegno automatico:
CMenu:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this menu CMenu:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this menu
Per le caselle di riepilogo di disegno automatico:
CListBox:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this list box CListBox:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this list box CListBox:CompareItem(LPCOMPAREITEMSTRUCT); // insert code to compare two items in this list box if LBS_SORT CListBox:DeleteItem(LPDELETEITEMSTRUCT); // insert code to delete an item from this list box
Per le caselle combinate di disegno automatico:
CComboBox:MeasureItem(LPMEASUREITEMSTRUCT); // insert code to measure the size of an item in this combo box CComboBox:DrawItem(LPDRAWITEMSTRUCT); // insert code to draw an item in this combo box CComboBox:CompareItem(LPCOMPAREITEMSTRUCT); // insert code to compare two items in this combo box if CBS_SORT CComboBox:DeleteItem(LPDELETEITEMSTRUCT); // insert code to delete an item from this combo box
Per informazioni dettagliate sulle strutture di disegno proprietario (DRAWITEMSTRUCT, MEASUREITEMSTRUCT, COMPAREITEMSTRUCT e DELETEITEMSTRUCT) vedere rispettivamente la documentazione di MFC per CWnd::OnDrawItem
, CWnd::OnMeasureItem
, CWnd::OnCompareItem
e CWnd::OnDeleteItem
.
Utilizzo dei menu e dei controlli di disegno automatico
Per i menu di disegno automatico, è necessario eseguire l'override dei metodi OnMeasureItem
e OnDrawItem
.
Per le caselle di riepilogo e caselle combinate di disegno automatico, è necessario eseguire l'override di OnMeasureItem
e OnDrawItem
. È necessario specificare lo stile LBS_OWNERDRAWVARIABLE per le caselle di riepilogo o CBS_OWNERDRAWVARIABLE stile per le caselle combinate nel modello di finestra di dialogo. Lo stile OWNERDRAWFIXED non funzionerà con gli elementi di disegno automatico perché l'altezza dell'elemento fisso viene determinata prima che i controlli di disegno automatico siano collegati alla casella di riepilogo. È possibile usare i metodi CListBox::SetItemHeight e CComboBox::SetItemHeight per superare questa limitazione.
Se si passa a uno stile OWNERDRAWVARIABLE, il sistema applicherà lo stile NOINTEGRALHEIGHT al controllo. Poiché il controllo non può calcolare un'altezza integrale con elementi di dimensioni variabili, lo stile predefinito di INTEGRALHEIGHT viene ignorato e il controllo è sempre NOINTEGRALHEIGHT. Se gli elementi hanno l'altezza fissata, è possibile evitare che gli elementi parziali vengano disegnati specificando la dimensione di controllo in modo che sia un moltiplicatore intero della dimensione dell'elemento.
Per le caselle di riepilogo e le caselle combinate di disegno automatico con lo stile LBS_SORT o CBS_SORT, è necessario eseguire l'override del OnCompareItem
metodo .
Per le caselle di riepilogo e le caselle combinate di disegno automatico, OnDeleteItem
in genere non viene sottoposto a override. È possibile eseguire l'override di OnDeleteItem
se si desidera eseguire dell'elaborazione speciale. Un caso in cui sarebbe applicabile è quando vengono archiviate della memoria aggiuntiva o altre risorse con ogni elemento casella di riepilogo o casella combinata.
Esempi di controlli e di menu di disegno automatico
L'esempio MFC Generale CTRLTEST fornisce esempi di un menu di disegno automatico e di una casella di riepilogo auto-disegno.
L'esempio più comune di un pulsante di disegno automatico è un pulsante bitmap. Un pulsante bitmap è un pulsante che mostra una, due o tre immagini bitmap per i diversi stati. Un esempio è disponibile nella classe MFC CBitmapButton.
Creazione di una sottoclasse dinamica
Talvolta è preferibile modificare la funzionalità di un oggetto già esistente. Negli esempi precedenti è stato necessario personalizzare i controlli prima che venissero creati. La creazione di una sottoclasse dinamica consente di personalizzare un controllo che è già stato creato.
La sottoclasse è il termine di Windows per sostituire l'oggetto WndProc di una finestra con un oggetto personalizzato WndProc
e chiamando il vecchio WndProc
per le funzionalità predefinite.
Questa operazione non deve essere confusa con la derivazione di classi di C++. Per chiarire, i termini C++ classe base e classe derivata sono analoghi alla superclasse e alla sottoclasse nel modello a oggetti di Windows. La derivazione di C++ con MFC e la creazione di una sottoclasse di Windows sono simili a livello funzionale, ad eccezione del fatto che C++ non supporta la creazione di una sottoclasse dinamica.
La classe CWnd
fornisce la connessione tra un oggetto C++ (derivato da CWnd
) e un oggetto finestra di Windows (noto come HWND
).
Esistono tre modi comuni in cui questi sono correlati:
CWnd
creaHWND
. È possibile modificare il comportamento in una classe derivata creando una classe derivata daCWnd
. VieneHWND
creato quando l'applicazione chiama CWnd::Create.L'applicazione associa un
CWnd
a unHWND
esistente. Il comportamento della finestra esistente non viene modificato. Si tratta di un caso di delega e reso possibile chiamando CWnd::Attach per eseguire l'alias di un oggetto esistenteHWND
a unCWnd
oggetto .CWnd
è collegato a unHWND
esistente ed è possibile modificare il comportamento in una classe derivata. Questa procedura è denominata creazione di una sottoclasse dinamica poiché viene modificato il comportamento e, di conseguenza la classe, di un oggetto Windows in fase di esecuzione.
È possibile ottenere la sottoclasse dinamica usando i metodi CWnd::SubclassWindow eCWnd::SubclassDlgItem.
Entrambe le routine associano un oggetto CWnd
a un HWND
esistente. SubclassWindow
accetta HWND
direttamente. SubclassDlgItem
è una funzione di supporto che accetta un ID di controllo e la finestra padre. SubclassDlgItem
è progettato per collegare gli oggetti C++ ai controlli finestra di dialogo creati da un modello di finestra di dialogo.
Vedere l'esempio CTRLTEST per diversi esempi di quando usare SubclassWindow
e SubclassDlgItem
.