Storlek på ComboBox rullgardinsbredd

De TComboBox komponent kombinerar en redigeringsruta med en rullbar "pick" -lista. Användare kan välja ett objekt från listan eller skriva direkt i redigera rutan.

Listrutan

När en kombinationsruta är i tappat tillstånd ritar Windows en listbox typ av kontroll för att visa kombinationsrutans objekt för val.

De DropDownCount-egendom anger det maximala antalet objekt som visas i listrutan.

De bredden på listrutan skulle som standard motsvara kombinationsrutans bredd.

När artiklarnas längd (på en sträng) överstiger komboboxens bredd visas artiklarna som avstängd!

TComboBox ger inte ett sätt att ställa in bredden på sin rullgardinslista :(

Fixa ComboBox rullgardinsbredd

Vi kan ställa in bredden på listrutan genom att skicka en special Windows-meddelande till kombinationsrutan. Meddelandet är CB_SETDROPPEDWIDTH och skickar minsta tillåtna bredd, i pixlar, för listboxen i en kombinationsruta.

Om du vill koda storleken på rullgardinslistan till, låt oss säga, 200 pixlar, kan du göra:


SendMessage (theComboBox. Handtag, CB_SETDROPPEDWIDTH, 200, 0); 
instagram viewer

Det här är bara ok om du är säker på att alla dina ComboBox. Objekten är inte längre än 200 px (när de ritas).

För att säkerställa att vi alltid har rullgardinsmenyn tillräckligt bred kan vi beräkna önskad bredd.

Här är en funktion för att få önskad bredd på listrutan och ställa in den:

procedur ComboBox_AutoWidth (const theComboBox: TCombobox); const
HORIZONTAL_PADDING = 4; var
itemsFullWidth: heltal; idx: heltal; artikelbredd: heltal; Börja
itemsFullWidth: = 0; // få det maximala som behövs med föremålen i dropdown-tillståndför idx: = 0 till -1 + theComboBox. Poster. Räkna doBörja
itemWidth: = theComboBox. Duk. Textbredd (theComboBox. Objekt [idx]); Inc (artikelbredd, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) sedan itemsFullWidth: = itemWidth; slutet; // ställa in bredden på rullgardinsmen om det behövsom (itemsFullWidth> theComboBox. Bredd) sedan. Börja// kontrollera om det skulle finnas en rullningslistaom theComboBox. DropDownCount sedan
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Handtag, CB_SETDROPPEDWIDTH, items FullWidth, 0); slutet; slutet; 

Bredden på den längsta strängen används för bredden på listrutan.

När ska jag ringa ComboBox_AutoWidth?
Om du fyller i listan över objekt (vid designtid eller när du skapar formuläret) kan du ringa ComboBox_AutoWidth-proceduren i formulärets onCreate händelsehanterare.

Om du dynamiskt ändrar listan med objekt i kombinationsrutan kan du ringa proceduren ComboBox_AutoWidth inuti OnDropDown händelsehanterare - inträffar när användaren öppnar rullgardinslistan.

Ett test
För ett test har vi 3 kombinationsrutor på ett formulär. Alla har objekt med texten bredare än den faktiska kombinationsrutans bredd. Den tredje kombinationsrutan är placerad nära den högra kanten av formulärets gräns.

Egenskapen Objekt, för detta exempel, är förfylld - vi kallar vår ComboBox_AutoWidth i OnCreate-händelseshanteraren för formuläret:

// Forms OnCreateprocedur TForm. FormCreate (avsändare: TObject); Börja
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); slutet; 

Vi har inte ringt ComboBox_AutoWidth för Combobox1 för att se skillnaden!

Observera att rullgardinsmenyn för Combobox2 när den körs kommer att vara bredare än Combobox2.

Hela rullgardinslistan är avskuren för "Nära höger kant placering"

För Combobox3, den som ligger nära höger kant, är rullgardinslistan avskuren.

Skicka CB_SETDROPPEDWIDTH kommer alltid att utöka listrutan till höger. När din kombobox är nära den högra kanten, skulle en utvidgning av listrutan till höger resultera i att listrutan skärs bort.

Vi måste på något sätt utöka listan till vänster när detta är fallet, inte till höger!

CB_SETDROPPEDWIDTH har inget sätt att ange i vilken riktning (vänster eller höger) att utöka listrutan.

Lösning: WM_CTLCOLORLISTBOX

Precis när rullgardinsmenyn ska visas skickar Windows WM_CTLCOLORLISTBOX-meddelandet till moderfönstret i en listruta - till vår kombinationsruta.

Att kunna hantera WM_CTLCOLORLISTBOX för den nästan högra komboboxen skulle lösa problemet.

The Almighty WindowProc
Varje VCL-kontroll exponerar egenskapen WindowProc - proceduren som svarar på meddelanden som skickas till kontrollen. Vi kan använda egenskapen WindowProc för att tillfälligt ersätta eller underklassera fönstret för kontrollen.

Här är vår modifierade WindowProc för Combobox3 (den nära högra kanten):

// modifierad ComboBox3 WindowProcprocedur TForm. ComboBox3WindowProc (var Meddelande: TMessage); var
cr, lbr: TRect; Börja// Rita listrutan med kombinerade objekt
om meddelande. Msg = WM_CTLCOLORLISTBOX sedan. Börja
GetWindowRect (ComboBox3.Handle, cr); // listbox rektangel
GetWindowRect (meddelande. LParam, lbr); // flytta den till vänster för att matcha höger kantom sp. Höger <> lbr. Rätt sedan
MoveWindow (meddelande. LParam, lbr. Vänster- (LBR. Höger clbr. Höger), lbr. Top, lbr. Höger LBR. Vänster, lbr. Nederst LBR. Överst, sant); slutetannan
ComboBox3WindowProcORIGINAL (Message); slutet; 

Om meddelandet som vår kombinationsruta får är WM_CTLCOLORLISTBOX får vi dess fönster rektangel, vi får också rektangeln i listrutan som ska visas (GetWindowRect). Om det verkar som att listrutan skulle visas mer till höger - flyttar vi den till vänster så att kombinationsrutan och listrutan till höger är samma. Så lätt som det :)

Om meddelandet inte är WM_CTLCOLORLISTBOX kallar vi helt enkelt den ursprungliga proceduren för meddelandeshantering för kombinationsrutan (ComboBox3WindowProcORIGINAL).

Slutligen kan allt detta fungera om vi har ställt in det korrekt (i OnCreate-händelseshanteraren för formuläret):

// Forms OnCreateprocedur TForm. FormCreate (avsändare: TObject); Börja
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // bifoga modifierat / anpassat WindowProc för ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; slutet; 

Var i formulärdeklarationen har vi (hela):

typ
TForm = klass(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;procedur FormCreate (avsändare: TObject); privat
ComboBox3WindowProcORIGINAL: TWndMethod; procedur ComboBox3WindowProc (var Meddelande: TMessage); offentlig{Offentliga förklaringar}slutet; 

Och det är allt. Alla hanteras :)

instagram story viewer