Dimensiunea lățimii în jos a ComboBox

Componenta TComboBox combină o casetă de editare cu o listă "pick" rulată. Utilizatorii pot selecta un element din listă sau tastați direct în caseta de editare.

Lista verticală

Când o casetă combo este în starea derulată, Windows desenează un tip de casetă de listă de control pentru a afișa elemente de casetă combo pentru selectare.

Proprietatea DropDownCount specifică numărul maxim de articole afișate în lista derulantă.

lățimea listei derulante ar fi, implicit, egală cu lățimea casetei combo.

Atunci când lungimea (a unui șir) de articole depășește lățimea combinatorului, elementele sunt afișate ca decupate!

TComboBox nu oferă o modalitate de a seta lățimea listei derulante :(

Fixarea Lățimii drop-down ComboBox

Putem seta lățimea listei derulante prin trimiterea unui mesaj special pentru Windows în caseta combo. Mesajul este CB_SETDROPPEDWIDTH și trimite lățimea minimă admisă, în pixeli, a casetei de listă a unei casete combo.

Pentru a coda dimensiunea listei derulante la, să zicem, 200 pixeli, puteți face:

 SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, 200, 0); 

Acest lucru este în regulă numai dacă sunteți sigur că toate articolele dvs.ComboBox.Nu sunt mai mari de 200 px (atunci când sunt desenate).

Pentru a ne asigura că avem întotdeauna afișarea listei derulante suficient de largă, putem calcula lățimea necesară.

Iată o funcție pentru a obține lățimea necesară a listei derulante și setați-o:

 procedură ComboBox_AutoWidth (const theComboBox: TCombobox); const HORIZONTAL_PADDING = 4; var itemsFullWidth: număr întreg; idx: număr întreg; itemWidth: integer; începe itemsFullWidth: = 0; // obțineți maximul necesar cu elementele în stare derulantă pentru idx: = 0 la -1 + theComboBox.Items.Count do începe itemWidth: = theComboBox.Canvas.TextWidth (theComboBox.Items [idx]); Inc (element lățime, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) apoi itemsFullWidth: = itemWidth; Sfârșit; // setați lățimea în jos, dacă este necesar dacă (itemsFullWidth> theComboBox.Width) apoi începe // verificați dacă ar exista o bară de defilare dacă theComboBox.DropDownCount < theComboBox.Items.Count apoi itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); Sfârșit; Sfârșit; 

Lățimea celui mai lung șir este utilizată pentru lățimea listei derulante.

Când să apelați ComboBox_AutoWidth?
Dacă completați lista elementelor (la momentul proiectării sau la crearea formularului), puteți apela procedura ComboBox_AutoWidth în interiorul formularului OnCreate organizatorul evenimentului.

Dacă schimbați dinamic lista de elemente din caseta combo, puteți apela procedura ComboBox_AutoWidth în interiorul OnDropDown handler de evenimente - apare când utilizatorul deschide lista derulantă.

Un test
Pentru un test, avem 3 cutii combo pe un formular. Toate au elemente cu textul lor mai larg decât lățimea combo-ului real. Cea de-a treia casetă combo este plasată lângă marginea din dreapta a marginii formularului.

Proprietatea Elementele, de exemplu, este completată în prealabil - apelăm la ComboBox_AutoWidth nostru în handler pentru evenimentele OnCreate pentru formularul:

 // Form OnCreate procedură TForm.FormCreate (Expeditor: TObject); începe ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); Sfârșit; 

Nu am apelat la ComboBox_AutoWidth pentru Combobox1 pentru a vedea diferența!

Rețineți că, atunci când este executat, lista derulantă pentru Combobox2 va fi mai largă decât Combobox2.

Întreaga listă derulantă este întreruptă pentru „Plasarea pe marginea dreaptă”

Pentru Combobox3, cel plasat lângă marginea dreaptă, lista derulantă este întreruptă.

Trimiterea CB_SETDROPPEDWIDTH va întinde întotdeauna caseta listă derulantă spre dreapta. Când combobox-ul dvs. este aproape de marginea dreaptă, extinderea casetei de listă mai mult spre dreapta ar duce la întreruperea afișării casetei de listă.

Trebuie să extindem cumva caseta de listă la stânga atunci când acesta este cazul, nu la dreapta!

CB_SETDROPPEDWIDTH nu are cum să specifice în ce direcție (stânga sau dreapta) să extindă caseta de listă.

Soluție: WM_CTLCOLORLISTBOX

Tocmai în momentul afișării listei derulante, Windows trimite mesajul WM_CTLCOLORLISTBOX către fereastra părinte a unei căsuțe de listă - la caseta noastră de combo.

Dacă puteți gestiona WM_CTLCOLORLISTBOX pentru comboboxul din partea dreaptă, ar rezolva problema.

Fereastra AtotputernicăProc
Fiecare control VCL expune proprietatea WindowProc - procedura care răspunde la mesajele trimise controlului. Putem folosi proprietatea WindowProc pentru a înlocui sau subclasa temporar procedura de control a ferestrei.

Iată WindowProc modificat pentru Combobox3 (cel de lângă marginea dreaptă):

 // ComboBox3 WindowProc modificat procedură TForm.ComboBox3WindowProc (var Mesaj: TMessage); var cr, lbr: TRect; începe // desenarea casetei de liste cu articole combobox dacă Message.Msg = WM_CTLCOLORLISTBOX atunci începe GetWindowRect (ComboBox3.Handle, cr); // dreptunghi casetă listă GetWindowRect (Message.LParam, lbr); // mutați-o spre stânga pentru a se potrivi cu chenarul drept dacă cr.Right lbr.Right apoi MoveWindow (Message.LParam, lbr.Left- (lbr.Right-clbr.Right), lbr.Top, lbr.Right-lbr.Left, lbr.Bottom-lbr.Top, True); Sfârșit altfel ComboBox3WindowProcORIGINAL (Message); Sfârșit; 

Dacă mesajul pe care îl primește caseta noastră combinată este WM_CTLCOLORLISTBOX obținem dreptunghiul ferestrei sale, obținem și dreptunghiul casetei de listă care va fi afișat (GetWindowRect). Dacă apare că caseta de listă ar apărea mai mult la dreapta - o mutăm la stânga, astfel încât caseta combo și caseta de listă marginea din dreapta să fie aceeași. La fel de ușor ca asta :)

Dacă mesajul nu este WM_CTLCOLORLISTBOX, apelăm pur și simplu la procedura originală de gestionare a mesajelor pentru caseta combo (ComboBox3WindowProcORIGINAL).

În cele din urmă, toate acestea pot funcționa dacă am setat-o ​​corect (în gestionarea evenimentelor OnCreate pentru formular):

 // Form OnCreate procedură TForm.FormCreate (Expeditor: TObject); începe ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // atașați WindowProc modificat / personalizat pentru ComboBox3 ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; Sfârșit; 

În declarația formularului avem (întreg):

 tip TForm = clasă(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox; procedură FormCreate (Expeditor: TObject); privat ComboBox3WindowProcORIGINAL: TWndMethod; procedură ComboBox3WindowProc (var Mesaj: TMessage); public Declarații publice Sfârșit; 

Si asta e. Toate gestionate :)