Dimensiunea lățimii în jos a ComboBox

TComboBox componenta combină o casetă de editare cu o listă de „alegere” derulabilă. 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 comenzilor, 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 trimitând o specială Mesaj Windows la 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:

instagram viewer

SendMessage (theComboBox). Mâner, CB_SETDROPPEDWIDTH, 200, 0); 

Acest lucru este în regulă numai dacă sunteți sigur că toți theComboBox. Articolele nu au mai mult 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. Articole. Numara doîncepe
itemWidth: = theComboBox. Canvas. Lățime text (theComboBox). Elemente [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 necesardacă (itemsFullWidth> theComboBox. Lățime) apoi. începe// verificați dacă ar exista o bară de defilaredacă theComboBox. DropDownCount 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ă sunaț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 OnCreateprocedură 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 la 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 casete de listă - la caseta noastră de combo.

Posibilitatea de a gestiona WM_CTLCOLORLISTBOX pentru comboboxul din dreapta aproape 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 modificatprocedură TForm. ComboBox3WindowProc (var Mesaj: TMessage); var
cr, lbr: TRect; începe// desenarea casetei de liste cu articole combobox
dacă Mesaj. Msg = WM_CTLCOLORLISTBOX apoi. începe
GetWindowRect (ComboBox3.Handle, cr); // dreptunghi casetă listă
GetWindowRect (Mesaj. LParam, lbr); // mutați-o spre stânga pentru a se potrivi cu dreaptadacă cr. Corect <> lbr. Dreapta apoi
MoveWindow (Mesaj. LParam, lbr. Stângace (LBR. Dreapta-clbr. Corect), lbr. Sus, lbr. Dreapta-LBR. Stânga, lbr. Bottom-LBR. Sus, Adevărat); Sfârșitaltfel
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ă se pare că caseta de listă ar apărea mai mult în 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 OnCreateprocedură 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 :)