The TComboBox komponenta združuje urejevalno polje z drsnim seznamom za izbiranje. Uporabniki lahko izberejo element s seznama ali ga vnesejo neposredno v polje za urejanje.
Spustni seznam
Ko je kombinirano polje v spuščenem stanju, Windows nariše vrsto polja s seznamom, da prikaže elemente kombiniranega polja za izbiro.
The Lastnost DropDownCount določa največje število elementov, prikazanih na spustnem seznamu.
The širina spustnega seznama bi bila privzeto enaka širini polja.
Ko dolžina (vrvice) elementov presega širino polja, se elementi prikažejo kot odrezani!
TComboBox ne ponuja načina nastavitve širine spustnega seznama :(
Popravljanje širine spustnega seznama ComboBox
Širino spustnega seznama lahko nastavimo tako, da pošljemo posebno Windows sporočilo do kombiniranega polja. Sporočilo je CB_SETDROPPEDWIDTH in pošlje najmanjšo dovoljeno širino seznama v slikovnem polju v pikslih.
Če želite trdo kodirati velikost spustnega seznama na, recimo, 200 slikovnih pik, lahko storite naslednje:
Pošlji sporočilo (theComboBox. Ročaj, CB_SETDROPPEDWIDTH, 200, 0);
To je v redu samo, če ste prepričani, da so vsi vaši theComboBox. Elementi niso daljši od 200 px (ko so narisani).
Če želimo zagotoviti, da je zaslon spustnega seznama vedno dovolj širok, lahko izračunamo potrebno širino.
Tu je funkcija, da dobite potrebno širino spustnega seznama in ga nastavite:
postopek ComboBox_AutoWidth (konst theComboBox: TCombobox); konst
HORIZONTAL_PADDING = 4; var
itemsFullWidth: celo število; idx: celo število; itemWidth: celo število; začeti
itemsFullWidth: = 0; // pridobite največje dovoljeno število elementov v spustnem stanjuza idx: = 0 do -1 + theComboBox. Predmeti. Štet storizačeti
itemWidth: = theComboBox. Platno. TextWidth (theComboBox. Predmeti [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); če (itemWidth> itemsFullWidth) torej itemsFullWidth: = itemWidth; konec; // po potrebi nastavite širino spuščače (itemsFullWidth> theComboBox. Širina) torej. začeti// preverite, ali bi obstajala drsna vrsticače theComboBox. DropDownCount torej
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); Pošlji sporočilo (theComboBox. Ročaj, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); konec; konec;
Širina najdaljšega niza se uporablja za širino spustnega seznama.
Kdaj poklicati ComboBox_AutoWidth?
Če predhodno izpolnite seznam elementov (v času načrtovanja ali pri ustvarjanju obrazca), lahko pokličete postopek ComboBox_AutoWidth znotraj obrazca OnCreate obdelovalec dogodkov.
Če dinamično spremenite seznam elementov kombiniranega polja, lahko pokličete postopek ComboBox_AutoWidth znotraj OnDropDown obdelovalec dogodkov - pojavi se, ko uporabnik odpre spustni seznam.
Preizkus
Za test imamo na obrazcu 3 kombinirane polja. Vsi imajo predmete, katerih besedilo je širše od dejanske širine polja. Tretji kombinirani okvir je nameščen blizu desnega roba oboda obrazca.
Lastnost Izdelki, na primer, je vnaprej napolnjena - v obrazcu za obdelavo dogodkov OnCreate pokličemo naš ComboBox_AutoWidth:
// Obrazec je OnCreatepostopek TForm. FormCreate (pošiljatelj: TObject); začeti
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); konec;
Nismo poklicali ComboBox_AutoWidth za Combobox1, da bi videli razliko!
Ko se zažene, bo spustni seznam za Combobox2 širši od Combobox2.
Celo spustni seznam je izrezan za "Umestitev blizu desnega roba"
Za Combobox3, ki je postavljen blizu desnega roba, je spustni seznam odrezan.
Pošiljanje CB_SETDROPPEDWIDTH bo vedno podaljšalo spustni seznam na desni. Če je vaš kombinirani predal blizu desnega roba, bo razširitev polja s seznamom bolj na desno povzročila, da se bo prikazal seznam seznama.
Seznam okenca moramo nekako razširiti na levo, ko je to tako, ne na desno!
CB_SETDROPPEDWIDTH ne more določiti, v katero smer (levo ali desno) razširiti polje s seznamom.
Rešitev: WM_CTLCOLORLISTBOX
Ravno ob prikazu spustnega seznama Windows pošlje sporočilo WM_CTLCOLORLISTBOX v nadrejeno okno seznama - v naš kombinirani okvir.
Če bi se spopadli z WM_CTLCOLORLISTBOX za kombinirani predal blizu desnega roba, bi to rešilo težavo.
Vsemogočno oknoProc
Vsak nadzor VCL izpostavi lastnost WindowProc - postopek, ki se odziva na sporočila, poslana krmilu. Lastnost WindowProc lahko uporabimo za začasno nadomestitev ali podrazvrstitev okenskega postopka nadzora.
Tu je naš spremenjeni WindowProc za Combobox3 (tisti blizu desnega roba):
// spremenjen ComboBox3 WindowProcpostopek TForm. ComboBox3WindowProc (var Sporočilo: TMessage); var
cr, lbr: TRect; začeti// risanje polja s seznamom elementov v polju
če sporočilo. Msg = WM_CTLCOLORLISTBOX, potem. začeti
GetWindowRect (ComboBox3.Handle, cr); // pravokotnik seznama polja
GetWindowRect (sporočilo. LParam, lbr); // premaknite ga v levo, da se ujema z desno mejoče cr. Desno <> lbr. Prav torej
MoveWindow (sporočilo. LParam, lbr. Levo- (lbr. Desno-clbr. Prav), lbr. Vrh, lbr. Desno lbr. Levo, lbr. Spodaj-lbr. Vrh, res); konecdrugače
ComboBox3WindowProcORIGINAL (sporočilo); konec;
Če je sporočilo, ki ga prejme naš kombinirani okvir, WM_CTLCOLORLISTBOX, dobimo pravokotnik njegovega okna, dobimo tudi pravokotnik seznama v polju (GetWindowRect). Če se zdi, da bi se seznam s seznamom pojavljal bolj na desni - ga premaknemo na levo, tako da je združena deska in meja polja z desnim robom enaka. Tako enostavno kot to :)
Če sporočilo ni WM_CTLCOLORLISTBOX, preprosto pokličemo izvirni postopek ravnanja s sporočili za kombinirano polje (ComboBox3WindowProcORIGINAL).
Končno lahko vse to deluje, če smo ga pravilno nastavili (v obrazcu za obdelavo dogodkov OnCreate za obrazec):
// Obrazec je OnCreatepostopek TForm. FormCreate (pošiljatelj: TObject); začeti
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // priložite spremenjen / prilagojen WindowProc za ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; konec;
Kje v deklaraciji obrazca imamo (celoto):
tip
TForm = razred(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;postopek FormCreate (pošiljatelj: TObject); zasebno
ComboBox3WindowProcORIGINAL: TWndMethod; postopek ComboBox3WindowProc (var Sporočilo: TMessage); javnosti{Javne izjave}konec;
In to je to. Vsi obravnavani :)