Det TComboBox komponent kombinerer en redigeringsboks med en rullbar "pick" -liste. Brugere kan vælge et element fra listen eller skrive direkte på rediger boks.
Drop Down List
Når en kombinationsboks er i rulletilstand, trækker Windows en listebokstype af kontrol til at vise kombinationsbokseelementer til valg.
Det DropDownCount-ejendom angiver det maksimale antal elementer, der vises på rullelisten.
Det bredde på rullelisten ville som standard svare til bredden på kombinationsboksen.
Når længden (af en streng) af emner overstiger komboboxens bredde, vises elementerne som afskåret!
TComboBox giver ikke en måde at indstille bredden på sin rulleliste :(
Fixing af ComboBox drop-down listebredde
Vi kan indstille bredden på rullelisten ved at sende en special Windows-besked til kombinationsboksen. Beskeden er CB_SETDROPPEDWIDTH og sender den tilladte minimumsbredde, i pixels, af listefeltet i en kombinationsboks.
Hvis du vil kode på størrelsen på rullelisten til, lad os sige, 200 pixels, kan du gøre:
SendMessage (theComboBox. Håndtag, CB_SETDROPPEDWIDTH, 200, 0);
Dette er kun ok, hvis du er sikker på, at al din ComboBox. Elementer er ikke længere end 200 px (når det tegnes).
For at sikre, at vi altid har rullemenuen nok nok bred, kan vi beregne den krævede bredde.
Her er en funktion til at få den krævede bredde på rullelisten og indstille den:
procedure ComboBox_AutoWidth (const theComboBox: TCombobox); const
HORIZONTAL_PADDING = 4; Var
itemsFullWidth: heltal; idx: heltal; itemBredde: heltal; begynde
itemsFullWidth: = 0; // få det maksimale behov for med elementerne i dropdown-tilstandtil idx: = 0 til -1 + theComboBox. Elementer. Tælle gørebegynde
itemWidth: = theComboBox. Lærred. TextWidth (theComboBox. Emner [idx]); Øk (artikelbredde, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) derefter itemsFullWidth: = itemWidth; ende; // indstil bredden på dropdown om nødvendigthvis (itemsFullWidth> theComboBox. Bredde) derefter. begynde// Kontroller, om der ville være en rullebjælkehvis theComboBox. DropDownCount derefter
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Håndtag, CB_SETDROPPEDWIDTH, items FullWidth, 0); ende; ende;
Bredden på den længste streng bruges til bredden på rullelisten.
Hvornår skal jeg ringe til ComboBox_AutoWidth?
Hvis du forudfylder listen over varer (på designtidspunktet eller når du opretter formularen), kan du ringe til ComboBox_AutoWidth-proceduren inde i formularens onCreate event handler.
Hvis du dynamisk ændrer listen over elementer i kombinationsboksen, kan du kalde proceduren ComboBox_AutoWidth inde i OnDropDown begivenhedshåndterer - opstår, når brugeren åbner rullelisten.
En test
For en test har vi 3 kombinationsbokse på en formular. Alle har emner med deres tekst mere bred end den faktiske kombinationsboksbredde. Den tredje kombinationsboks er placeret nær højre kant af formens kant.
Items-egenskaben, for dette eksempel, er forudfyldt - vi kalder vores ComboBox_AutoWidth i OnCreate-begivenhedshåndtereren for formularen:
// Forms OnCreateprocedure TForm. FormCreate (Afsender: TObject); begynde
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); ende;
Vi har ikke kaldet ComboBox_AutoWidth til Combobox1 for at se forskellen!
Bemærk, at rullelisten for Combobox2, når den køres, vil være bredere end Combobox2.
Hele rullelisten er afskåret til "placering i nærheden af højre kant"
For Combobox3, den, der er placeret nær højre kant, er rullelisten afskåret.
Afsendelse af CB_SETDROPPEDWIDTH vil altid udvide rullelisten til højre. Når din komboboks er tæt på den højre kant, ville udvidelse af listefeltet mere til højre resultere i, at visningen af listefeltet bliver afskåret.
Vi skal på en eller anden måde udvide listefeltet til venstre, når dette er tilfældet, ikke til højre!
CB_SETDROPPEDWIDTH har ingen måde at specificere i hvilken retning (venstre eller højre) at udvide listefeltet.
Løsning: WM_CTLCOLORLISTBOX
Lige når rullelisten skal vises sender Windows WM_CTLCOLORLISTBOX meddelelsen til det overordnede vindue i en listekasse - til vores kombinationsboks.
At kunne håndtere WM_CTLCOLORLISTBOX til den næste højre kant-komboboks ville løse problemet.
Det Almægtige WindowProc
Hver VCL-kontrol udsætter egenskaben WindowProc - proceduren, der svarer til meddelelser, der er sendt til kontrollen. Vi kan bruge egenskaben WindowProc til midlertidigt at erstatte eller underklasse kontrollens vinduesprocedure.
Her er vores ændrede WindowProc til Combobox3 (den nær højre kant):
// ændret ComboBox3 WindowProcprocedure TForm. ComboBox3WindowProc (Var Meddelelse: TMessage); Var
cr, lbr: TRect; begynde// tegning af listefeltet med combobox-genstande
hvis besked. Msg = WM_CTLCOLORLISTBOX derefter. begynde
GetWindowRect (ComboBox3.Handle, cr); // listefeltets rektangel
GetWindowRect (besked. LParam, lbr); // flyt det til venstre for at matche højre kanthvis cr. Højre <> lbr. Ret derefter
MoveWindow (besked. LParam, lbr. Venstre- (LBR. Højreklik clbr. Højre), lbr. Top, lbr. Højreklik LBR. Venstre, lbr. Bottom-LBR. Top, sandt); endeandet
ComboBox3WindowProcORIGINAL (besked); ende;
Hvis meddelelsen, som vores kombinationsboks modtager, er WM_CTLCOLORLISTBOX, vi får vinduet til rektangel, får vi også rektanglet i den listeboks, der skal vises (GetWindowRect). Hvis det ser ud til, at listefeltet vises mere til højre - flytter vi det til venstre, så kombinationsboksen og listekassens højre kant er den samme. Så let som det :)
Hvis meddelelsen ikke er WM_CTLCOLORLISTBOX, kalder vi blot den originale procedure for meddelelseshåndtering for combo-boksen (ComboBox3WindowProcORIGINAL).
Endelig kan alt dette fungere, hvis vi har indstillet det korrekt (i OnCreate-begivenhedshåndtereren til formularen):
// Forms OnCreateprocedure TForm. FormCreate (Afsender: TObject); begynde
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // vedhæft ændret / brugerdefineret WindowProc til ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; ende;
Hvor i formularens erklæring vi har (hele):
type
TForm = klasse(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;procedure FormCreate (Afsender: TObject); privat
ComboBox3WindowProcORIGINAL: TWndMethod; procedure ComboBox3WindowProc (Var Meddelelse: TMessage); offentlig{Offentlige erklæringer}ende;
Og det er det. Alle håndteres :)