Formaat van de keuzelijstbreedte van de ComboBox aanpassen

De TComboBox-component combineert een bewerkingsvak met een schuifbare "keuzelijst". Gebruikers kunnen een item uit de lijst selecteren of rechtstreeks in het bewerkingsvak typen.

Keuzelijst

Wanneer een keuzelijst in de vervolgkeuzelijst staat, tekent Windows een type keuzelijst om keuzelijstitems weer te geven voor selectie.

De Eigenschap DropDownCount geeft het maximale aantal items aan dat wordt weergegeven in de vervolgkeuzelijst.

De breedte van de vervolgkeuzelijst zou standaard gelijk zijn aan de breedte van de keuzelijst.

Wanneer de lengte (van een string) van items de breedte van de combobox overschrijdt, worden de items weergegeven als afgesneden!

TComboBox biedt geen manier om de breedte van de vervolgkeuzelijst in te stellen :(

De breedte van de vervolgkeuzelijst ComboBox repareren

We kunnen de breedte van de vervolgkeuzelijst instellen door een speciaal Windows-bericht naar de keuzelijst te verzenden. Het bericht is CB_SETDROPPEDWIDTH en verzendt de minimaal toegestane breedte, in pixels, van de keuzelijst van een keuzelijst.

Om de grootte van de vervolgkeuzelijst te laten coderen tot, laten we zeggen, 200 pixels, kunt u het volgende doen:

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

Dit is alleen ok als u zeker weet dat al uw theComboBox.Items zijn niet langer dan 200 px (wanneer getekend).

Om ervoor te zorgen dat de vervolgkeuzelijst altijd voldoende breed wordt weergegeven, kunnen we de vereiste breedte berekenen.

Hier is een functie om de vereiste breedte van de vervolgkeuzelijst te krijgen en in te stellen:

 procedure ComboBox_AutoWidth (const theComboBox: TCombobox); const HORIZONTAL_PADDING = 4; var itemsFullWidth: geheel getal; idx: geheel getal; itemWidth: geheel getal; beginnen itemsFullWidth: = 0; // haal het maximale aantal benodigde items in de vervolgkeuzelijst voor idx: = 0 naar -1 + theComboBox.Items.Count Doen beginnen itemWidth: = theComboBox.Canvas.TextWidth (theComboBox.Items [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) vervolgens itemsFullWidth: = itemWidth; einde; // stel zo nodig de breedte van de vervolgkeuzelijst in als (itemsFullWidth> theComboBox.Width) vervolgens beginnen // controleer of er een schuifbalk zou zijn als theComboBox.DropDownCount < theComboBox.Items.Count vervolgens itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); einde; einde; 

De breedte van de langste tekenreeks wordt gebruikt voor de breedte van de vervolgkeuzelijst.

Wanneer ComboBox_AutoWidth te bellen?
Als u de lijst met items vooraf invult (tijdens het ontwerpen of bij het maken van het formulier), kunt u de procedure ComboBox_AutoWidth in de form OnCreate event handler.

Als u de lijst met items in de keuzelijst dynamisch wijzigt, kunt u de procedure ComboBox_AutoWidth in de OnDropDown gebeurtenishandler - treedt op wanneer de gebruiker de vervolgkeuzelijst opent.

Een toets
Voor een test hebben we 3 keuzelijsten op een formulier. Alle items hebben een bredere tekst dan de werkelijke breedte van het keuzevak. De derde keuzelijst wordt aan de rechterkant van de rand van het formulier geplaatst.

De eigenschap Items is voor dit voorbeeld vooraf ingevuld - we roepen onze ComboBox_AutoWidth in de OnCreate-gebeurtenishandler op voor het formulier:

 // Form's OnCreate procedure TForm.FormCreate (afzender: TObject); beginnen ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); einde; 

We hebben ComboBox_AutoWidth voor Combobox1 niet aangeroepen om het verschil te zien!

Merk op dat, wanneer uitgevoerd, de vervolgkeuzelijst voor Combobox2 breder is dan Combobox2.

De volledige vervolgkeuzelijst is afgebroken voor "plaatsing bijna rechts"

Voor Combobox3, degene die aan de rechterkant is geplaatst, wordt de vervolgkeuzelijst afgesneden.

Als u de CB_SETDROPPEDWIDTH verzendt, wordt de vervolgkeuzelijst altijd naar rechts uitgebreid. Wanneer uw combobox zich aan de rechterkant bevindt, zou het uitbreiden van de keuzelijst naar rechts resulteren in het afsnijden van de weergave van de keuzelijst.

We moeten de lijst op de een of andere manier naar links uitbreiden als dit het geval is, niet naar rechts!

De CB_SETDROPPEDWIDTH kan niet aangeven in welke richting (links of rechts) de keuzelijst moet worden uitgebreid.

Oplossing: WM_CTLCOLORLISTBOX

Net wanneer de vervolgkeuzelijst moet worden weergegeven, stuurt Windows het bericht WM_CTLCOLORLISTBOX naar het bovenliggende venster van een keuzelijst - naar onze keuzelijst.

Het probleem oplossen met de WM_CTLCOLORLISTBOX voor de bijna-rechtse combobox.

The Almighty WindowProc
Elk VCL-besturingselement toont de eigenschap WindowProc - de procedure die reageert op berichten die naar het besturingselement worden verzonden. We kunnen de eigenschap WindowProc gebruiken om de vensterprocedure van het besturingselement tijdelijk te vervangen of te subklasseeren.

Hier is onze aangepaste WindowProc voor Combobox3 (degene aan de rechterkant):

 // gemodificeerde ComboBox3 WindowProc procedure TForm.ComboBox3WindowProc (var Bericht: TMessage); var cr, lbr: TRect; beginnen // tekening van de keuzelijst met combobox-items als Message.Msg = WM_CTLCOLORLISTBOX dan beginnen GetWindowRect (ComboBox3.Handle, cr); // keuzelijst rechthoek GetWindowRect (Message.LParam, lbr); // verplaats deze naar links om overeen te komen met de rechterrand als cr.Right lbr.Right vervolgens MoveWindow (Message.LParam, lbr.Left- (lbr.Right-clbr.Right), lbr.Top, lbr.Right-lbr.Left, lbr.Bottom-lbr.Top, True); einde anders ComboBox3WindowProcORIGINAL (Message); einde; 

Als het bericht dat onze keuzelijst ontvangt WM_CTLCOLORLISTBOX is, krijgen we de rechthoek van het venster, krijgen we ook de rechthoek van de lijst die moet worden weergegeven (GetWindowRect). Als het lijkt dat de keuzelijst meer naar rechts lijkt - we verplaatsen hem naar links zodat de keuzelijst met keuzelijst en rechterrand van de keuzelijst hetzelfde zijn. Zo eenvoudig als dat :)

Als het bericht niet WM_CTLCOLORLISTBOX is, bellen we eenvoudigweg de oorspronkelijke procedure voor het verwerken van berichten voor de keuzelijst (ComboBox3WindowProcORIGINAL).

Ten slotte kan dit allemaal werken als we het correct hebben ingesteld (in de OnCreate-gebeurtenishandler voor het formulier):

 // Form's OnCreate procedure TForm.FormCreate (afzender: TObject); beginnen ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // aangepaste / aangepaste WindowProc voor ComboBox3 bijvoegen ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; einde; 

Waar we in de verklaring van het formulier (geheel) hebben:

 type TForm = klasse(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox; procedure FormCreate (afzender: TObject); privaat ComboBox3WindowProcORIGINAL: TWndMethod; procedure ComboBox3WindowProc (var Bericht: TMessage); openbaar Publieke verklaringen einde; 

En dat is het. Alles afgehandeld :)