Il TComboBox Il componente combina una casella di modifica con un elenco "prelievo" scorrevole. Gli utenti possono selezionare un elemento dall'elenco o digitare direttamente in casella di modifica.
Menu `A tendina
Quando una casella combinata si trova nello stato a discesa Windows disegna un tipo di controllo casella di riepilogo per visualizzare gli elementi della casella combinata per la selezione.
Il Proprietà DropDownCount specifica il numero massimo di elementi visualizzati nell'elenco a discesa.
Il larghezza dell'elenco a discesa sarebbe, per impostazione predefinita, uguale alla larghezza della casella combinata.
Quando la lunghezza (di una stringa) di elementi supera la larghezza della casella combinata, gli elementi vengono visualizzati come troncati!
TComboBox non fornisce un modo per impostare la larghezza del suo elenco a discesa :(
Correzione della larghezza dell'elenco a discesa ComboBox
Possiamo impostare la larghezza dell'elenco a discesa inviando uno speciale Messaggio di Windows
nella casella combinata. Il messaggio è CB_SETDROPPEDWIDTH e invia la larghezza minima consentita, in pixel, della casella di riepilogo di una casella combinata.Per codificare le dimensioni dell'elenco a discesa su, diciamo, 200 pixel, è possibile eseguire:
SendMessage (theComboBox. Maniglia, CB_SETDROPPEDWIDTH, 200, 0);
Questo va bene solo se sei sicuro di tutto il theComboBox. Gli oggetti non superano i 200 px (se disegnati).
Per essere sicuri che l'elenco a discesa sia sempre sufficientemente largo, possiamo calcolare la larghezza richiesta.
Ecco una funzione per ottenere la larghezza richiesta dell'elenco a discesa e impostarla:
procedura ComboBox_AutoWidth (const theComboBox: TCombobox); const
HORIZONTAL_PADDING = 4; var
itemsFullWidth: intero; idx: intero; itemWidth: intero; inizio
itemsFullWidth: = 0; // ottieni il massimo necessario con degli articoli nello stato a discesaper idx: = 0 per -1 + theComboBox. Elementi. Contare fareinizio
itemWidth: = theComboBox. Tela. TextWidth (theComboBox. Articoli [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) poi itemsFullWidth: = itemWidth; fine; // imposta la larghezza del menu a discesa, se necessarioSe (itemsFullWidth> theComboBox. Larghezza) quindi. inizio// controlla se ci sarebbe una barra di scorrimentoSe theComboBox. DropDownCount poi
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Maniglia, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); fine; fine;
La larghezza della stringa più lunga viene utilizzata per la larghezza dell'elenco a discesa.
Quando chiamare ComboBox_AutoWidth?
Se si precompila l'elenco degli elementi (in fase di progettazione o durante la creazione del modulo) è possibile chiamare la procedura ComboBox_AutoWidth all'interno del modulo OnCreate gestore di eventi.
Se si modifica dinamicamente l'elenco degli elementi della casella combinata, è possibile chiamare la procedura ComboBox_AutoWidth all'interno del OnDropDown gestore eventi: si verifica quando l'utente apre l'elenco a discesa.
Un test
Per un test, abbiamo 3 caselle combinate su un modulo. Tutti hanno elementi con il loro testo più ampio della larghezza effettiva della casella combinata. La terza casella combinata viene posizionata vicino al bordo destro del bordo del modulo.
La proprietà Items, in questo esempio, è precompilata: chiamiamo ComboBox_AutoWidth nel gestore eventi OnCreate per il modulo:
// Form's OnCreateprocedura TForm. FormCreate (Mittente: TObject); inizio
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); fine;
Non abbiamo chiamato ComboBox_AutoWidth per Combobox1 per vedere la differenza!
Si noti che, quando eseguito, l'elenco a discesa per Combobox2 sarà più ampio di Combobox2.
L'intero elenco a discesa viene tagliato per "Posizionamento sul bordo destro"
Per Combobox3, quello posizionato vicino al bordo destro, l'elenco a discesa viene tagliato.
L'invio di CB_SETDROPPEDWIDTH estenderà sempre la casella di riepilogo a discesa a destra. Quando la casella combinata si trova vicino al bordo destro, l'estensione della casella di riepilogo più a destra comporterebbe il taglio della visualizzazione della casella di riepilogo.
Dobbiamo in qualche modo estendere la casella di riepilogo a sinistra in questo caso, non a destra!
CB_SETDROPPEDWIDTH non ha modo di specificare in quale direzione (sinistra o destra) estendere la casella di riepilogo.
Soluzione: WM_CTLCOLORLISTBOX
Proprio quando viene visualizzato l'elenco a discesa, Windows invia il messaggio WM_CTLCOLORLISTBOX alla finestra principale di una casella di riepilogo, alla nostra casella combinata.
Essere in grado di gestire WM_CTLCOLORLISTBOX per la casella combinata sul bordo destro dovrebbe risolvere il problema.
The Onnipotente WindowProc
Ogni controllo VCL espone la proprietà WindowProc - la procedura che risponde ai messaggi inviati al controllo. È possibile utilizzare la proprietà WindowProc per sostituire o sottoclassare temporaneamente la procedura window del controllo.
Ecco il nostro WindowProc modificato per Combobox3 (quello vicino al bordo destro):
// modificato ComboBox3 WindowProcprocedura TForm. ComboBox3WindowProc (var Messaggio: TMessage); var
cr, lbr: TRect; inizio// disegna la casella di riepilogo con gli elementi della casella combinata
se messaggio. Msg = WM_CTLCOLORLISTBOX quindi. inizio
GetWindowRect (ComboBox3.Handle, cr); // rettangolo casella di riepilogo
GetWindowRect (messaggio. LParam, lbr); // spostalo a sinistra per abbinare il bordo destroSe cr. Destra <> lbr. Giusto poi
MoveWindow (messaggio. LParam, lbr. Sinistra (LBR. Destro clbr. A destra), lbr. In alto, lbr. Destra-LBR. Sinistra, lbr. Bottom-LBR. Top, True); finealtro
ComboBox3WindowProcORIGINAL (Messaggio); fine;
Se il messaggio ricevuto dalla nostra casella combinata è WM_CTLCOLORLISTBOX, otteniamo il rettangolo della finestra, otteniamo anche il rettangolo della casella di riepilogo da visualizzare (GetWindowRect). Se sembra che la casella di riepilogo appaia più a destra, la spostiamo a sinistra in modo che la casella combinata e il bordo destro della casella di riepilogo siano uguali. Facile come quello :)
Se il messaggio non è WM_CTLCOLORLISTBOX, chiamiamo semplicemente la procedura di gestione dei messaggi originale per la casella combinata (ComboBox3WindowProcORIGINAL).
Infine, tutto ciò può funzionare se lo abbiamo impostato correttamente (nel gestore eventi OnCreate per il modulo):
// Form's OnCreateprocedura TForm. FormCreate (Mittente: TObject); inizio
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // collega WindowProc modificato / personalizzato per ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; fine;
Dove nella dichiarazione del modulo abbiamo (intero):
genere
TForm = classe(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;procedura FormCreate (Mittente: TObject); privato
ComboBox3WindowProcORIGINAL: TWndMethod; procedura ComboBox3WindowProc (var Messaggio: TMessage); pubblico{Dichiarazioni pubbliche}fine;
E questo è tutto. Tutto gestito :)