Størrelse på ComboBox rullegardinbredde

De TComboBox komponent kombinerer en redigeringsboks med en rullbar "velg" -liste. Brukere kan velge et element fra listen eller skrive direkte inn i redigeringsboks.

Nedtrekksliste

Når en kombinasjonsboks er i nedtalt tilstand, tegner Windows en listebokstype for kontroll for å vise kombinasjonsbokselementer for valg.

De DropDownCount-eiendom angir maksimalt antall elementer som vises i rullegardinlisten.

De bredden på rullegardinlisten vil som standard være lik bredden på kombinasjonsboksen.

Når lengden (på en streng) på elementer overstiger bredden på combobox, vises varene som avskåret!

TComboBox gir ikke en måte å angi bredden på rullegardinlisten :(

Fiksere ComboBox-rullegardinlistens bredde

Vi kan angi bredden på rullegardinlisten ved å sende en spesiell Windows-melding til kombinasjonsboksen. Meldingen er CB_SETDROPPEDWIDTH og sender minste tillatte bredde, i piksler, av listeboksen til en kombinasjonsboks.

Hvis du vil hardkode størrelsen på nedtrekkslisten til, la oss si, 200 piksler, kan du gjøre:

instagram viewer

SendMessage (theComboBox. Håndtak, CB_SETDROPPEDWIDTH, 200, 0); 

Dette er bare ok hvis du er sikker på at all din ComboBox. Varene er ikke lenger enn 200 px (når tegnet).

For å sikre at vi alltid har rullegardinmenyen nok nok til, kan vi beregne ønsket bredde.

Her er en funksjon for å få ønsket bredde på rullegardinlisten og angi den:

fremgangsmåte ComboBox_AutoWidth (konst theComboBox: TCombobox); konst
HORIZONTAL_PADDING = 4; Var
itemsFullWidth: heltall; idx: heltall; itemBredde: heltall; begynne
itemsFullWidth: = 0; // få maksimalt behov for med elementene i nedtrekksstatustil idx: = 0 til -1 + theComboBox. Elementer. Telle gjørebegynne
itemWidth: = theComboBox. Lerret. TextWidth (theComboBox. Elementer [idx]); Øk (itemBredde, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) deretter itemsFullWidth: = itemWidth; slutt; // angi bredden på rullegardin hvis det er nødvendighvis (itemsFullWidth> theComboBox. Bredde) da. begynne// sjekk om det ville være en rullefelthvis theComboBox. DropDownCount deretter
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Håndtak, CB_SETDROPPEDWIDTH, items FullWidth, 0); slutt; slutt; 

Bredden på den lengste strengen brukes for bredden på rullegardinlisten.

Når skal jeg ringe ComboBox_AutoWidth?
Hvis du forhåndsutfyller listen over elementer (på designtidspunktet eller når du oppretter skjemaet), kan du ringe ComboBox_AutoWidth-prosedyren i skjemaets onCreate arrangementshåndterer.

Hvis du dynamisk endrer listen over elementer i kombinasjonsboksen, kan du ringe prosedyren ComboBox_AutoWidth inne i OnDropDown hendelseshåndterer - oppstår når brukeren åpner rullegardinlisten.

En prøve
For en test har vi 3 kombinasjonsbokser på et skjema. Alle har elementer med teksten bredere enn den faktiske kombinasjonsboksen. Den tredje kombinasjonsboksen er plassert nær høyre kant av skjemaets grense.

Items-egenskapen, for dette eksempelet, er forhåndsutfylt - vi kaller ComboBox_AutoWidth i OnCreate-hendelsesbehandleren for skjemaet:

// Forms OnCreatefremgangsmåte TForm. FormCreate (avsender: TObject); begynne
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); slutt; 

Vi har ikke kalt ComboBox_AutoWidth for Combobox1 for å se forskjellen!

Vær oppmerksom på at rullegardinlisten for Combobox2 når den kjøres vil være bredere enn Combobox2.

Hele rullegardinlisten er avskåret for "nær høyre kantplassering"

For Combobox3, den som er plassert nær høyre kant, er rullegardinlisten avskåret.

Sending av CB_SETDROPPEDWIDTH vil alltid utvide rullegardinlisten til høyre. Når comboboxen din er i nærheten av høyre kant, vil utvidelse av listeboksen til høyre føre til at visningen av listeboksen blir avskåret.

Vi må på en eller annen måte utvide listeboksen til venstre når dette er tilfelle, ikke til høyre!

CB_SETDROPPEDWIDTH har ingen måte å spesifisere i hvilken retning (venstre eller høyre) for å utvide listeboksen.

Løsning: WM_CTLCOLORLISTBOX

Akkurat når rullegardinlisten skal vises, sender Windows WM_CTLCOLORLISTBOX-meldingen til hovedvinduet i en listeboks - til kombinasjonsboksen vår.

Å kunne håndtere WM_CTLCOLORLISTBOX for den nærmeste høyresidekombinasjonen ville løse problemet.

The Almighty WindowProc
Hver VCL-kontroll eksponerer WindowProc-egenskapen - prosedyren som svarer på meldinger som er sendt til kontrollen. Vi kan bruke WindowProc-egenskapen til midlertidig å erstatte eller underklasse vindusprosedyren til kontrollen.

Her er vår modifiserte WindowProc for Combobox3 (den nær høyre kant):

// modifisert ComboBox3 WindowProcfremgangsmåte TForm. ComboBox3WindowProc (Var Melding: TMessage); Var
cr, lbr: TRECT; begynne// tegne listeboksen med combobox-elementer
hvis melding. Msg = WM_CTLCOLORLISTBOX da. begynne
GetWindowRect (ComboBox3.Handle, cr); // listeskrinets rektangel
GetWindowRect (melding. LParam, lbr); // flytt den til venstre for å matche høyre kanthvis cr. Til høyre <> lbr. Ikke sant deretter
MoveWindow (melding. LParam, lbr. Venstre- (LBR. Høyre-clbr. Til høyre), lbr. Topp, lbr. Høyre-LBR. Venstre, lbr. Bunn-LBR. Topp, sant); sluttellers
ComboBox3WindowProcORIGINAL (Message); slutt; 

Hvis meldingen vår kombinasjonsboks mottar er WM_CTLCOLORLISTBOX vi får vinduets rektangel, får vi også rektangelet til listeboksen som skal vises (GetWindowRect). Hvis det ser ut til at listeboksen vil vises mer til høyre - flytter vi den til venstre slik at kombinasjonsboksen og listekassens høyre kant er den samme. Så enkelt som det :)

Hvis meldingen ikke er WM_CTLCOLORLISTBOX, kaller vi bare den opprinnelige prosedyren for meldingshåndtering for kombinasjonsboksen (ComboBox3WindowProcORIGINAL).

Endelig kan alt dette fungere hvis vi har satt det riktig (i OnCreate hendelsesbehandler for skjemaet):

// Forms OnCreatefremgangsmåte TForm. FormCreate (avsender: TObject); begynne
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // fest modifisert / tilpasset WindowProc for ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; slutt; 

Hvor i skjemaerklæringen vi har (hele):

type
TForm = klasse(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;fremgangsmåte FormCreate (avsender: TObject); privat
ComboBox3WindowProcORIGINAL: TWndMethod; fremgangsmåte ComboBox3WindowProc (Var Melding: TMessage); offentlig{Offentlige erklæringer}slutt; 

Og det er det. Alt håndtert :)