Dimensionierung der ComboBox-Dropdown-Breite

Die TComboBox-Komponente kombiniert ein Bearbeitungsfeld mit einer scrollbaren Auswahlliste. Benutzer können ein Element aus der Liste auswählen oder direkt in das Bearbeitungsfeld eingeben.

Dropdown-Liste

Wenn sich ein Kombinationsfeld im Dropdown-Status befindet, zeichnet Windows einen Listenfeld-Steuerungstyp, um Kombinationsfeldelemente zur Auswahl anzuzeigen.

Das DropDownCount-Eigenschaft Gibt die maximale Anzahl der in der Dropdown-Liste angezeigten Elemente an.

Das Breite der Dropdown-Liste entspricht standardmäßig der Breite des Kombinationsfelds.

Wenn die Länge (einer Zeichenfolge) von Elementen die Breite des Kombinationsfelds überschreitet, werden die Elemente als abgeschnitten angezeigt!

TComboBox bietet keine Möglichkeit, die Breite der Dropdown-Liste festzulegen :(

Korrigieren der Breite der ComboBox-Dropdown-Liste

Sie können die Breite der Dropdown-Liste festlegen, indem Sie eine spezielle Windows-Nachricht an das Kombinationsfeld senden. Die Nachricht ist CB_SETDROPPEDWIDTH und sendet die minimal zulässige Breite des Listenfelds eines Kombinationsfelds in Pixel.

Um die Größe der Dropdown-Liste auf beispielsweise 200 Pixel fest zu codieren, können Sie Folgendes tun:

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

Dies ist nur in Ordnung, wenn Sie sicher sind, dass alle Ihre theComboBox.Items nicht länger als 200 px sind (wenn sie gezeichnet sind)..

Um sicherzustellen, dass die Dropdown-Liste immer breit genug ist, können wir die erforderliche Breite berechnen.

Mit der folgenden Funktion können Sie die gewünschte Breite der Dropdown-Liste ermitteln und festlegen:

 Verfahren ComboBox_AutoWidth (const theComboBox: TCombobox); const HORIZONTAL_PADDING = 4; var itemsFullWidth: integer; idx: integer; itemWidth: Ganzzahl; Start itemsFullWidth: = 0; // Erhalte das Maximum, das mit den Elementen im Dropdown-Status benötigt wird zum idx: = 0 zu -1 + theComboBox.Items.Count tun Start itemWidth: = theComboBox.Canvas.TextWidth (theComboBox.Items [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) dann itemsFullWidth: = itemWidth; Ende; // Legen Sie die Breite der Dropdown-Liste fest, falls erforderlich wenn (itemsFullWidth> theComboBox.Width) dann Start // überprüfe, ob es eine Bildlaufleiste geben würde wenn theComboBox.DropDownCount < theComboBox.Items.Count dann itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); Ende; Ende; 

Die Breite der längsten Zeichenfolge wird für die Breite der Dropdown-Liste verwendet.

Wann ist ComboBox_AutoWidth aufzurufen??
Wenn Sie die Liste der Elemente vorab ausfüllen (zur Entwurfszeit oder beim Erstellen des Formulars), können Sie die ComboBox_AutoWidth-Prozedur innerhalb des Formulars aufrufen OnCreate Ereignishandler.

Wenn Sie die Liste der Kombinationsfeldelemente dynamisch ändern, können Sie die Prozedur ComboBox_AutoWidth in der aufrufen OnDropDown Ereignishandler - tritt auf, wenn der Benutzer die Dropdown-Liste öffnet.

Ein Test
Für einen Test haben wir 3 Kombinationsfelder in einem Formular. Bei allen Elementen ist der Text breiter als die tatsächliche Breite des Kombinationsfelds. Das dritte Kombinationsfeld befindet sich in der Nähe des rechten Randes des Formulars.

Die Items-Eigenschaft für dieses Beispiel ist bereits ausgefüllt. Wir rufen unsere ComboBox_AutoWidth im OnCreate-Ereignishandler für das folgende Formular auf:

 // Formulars OnCreate Verfahren TForm.FormCreate (Absender: TObject); Start ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); Ende; 

Wir haben ComboBox_AutoWidth für Combobox1 nicht aufgerufen, um den Unterschied zu erkennen!

Beachten Sie, dass die Dropdown-Liste für Combobox2 beim Ausführen breiter ist als für Combobox2.

Die gesamte Dropdown-Liste ist für "Platzierung am rechten Rand" abgeschnitten.

Bei der Combobox3, die sich in der Nähe des rechten Randes befindet, ist die Dropdown-Liste abgeschnitten.

Durch das Senden von CB_SETDROPPEDWIDTH wird das Dropdown-Listenfeld immer nach rechts erweitert. Wenn sich Ihre Combobox in der Nähe des rechten Randes befindet und das Listenfeld weiter nach rechts erweitert wird, wird die Anzeige des Listenfelds abgeschnitten.

Wir müssen das Listenfeld irgendwie nach links erweitern, wenn dies der Fall ist, nicht nach rechts!

Mit CB_SETDROPPEDWIDTH kann nicht angegeben werden, in welche Richtung (links oder rechts) das Listenfeld erweitert werden soll.

Lösung: WM_CTLCOLORLISTBOX

Gerade wenn die Dropdown-Liste angezeigt werden soll, sendet Windows die Meldung WM_CTLCOLORLISTBOX an das übergeordnete Fenster eines Listenfelds - an unser Kombinationsfeld.

In der Lage zu sein, die WM_CTLCOLORLISTBOX für die Combobox am rechten Rand zu handhaben, würde das Problem lösen.

Das allmächtige FensterProc
Jedes VCL-Steuerelement macht die WindowProc-Eigenschaft verfügbar - die Prozedur, die auf an das Steuerelement gesendete Nachrichten reagiert. Wir können die WindowProc-Eigenschaft verwenden, um die Fensterprozedur des Steuerelements vorübergehend zu ersetzen oder eine Unterklasse zu erstellen.

Hier ist unser modifizierter WindowProc für Combobox3 (der am rechten Rand):

 // ComboBox3 WindowProc geändert Verfahren TForm.ComboBox3WindowProc (var Nachricht: TMessage); var cr, lbr: TRect; Start // Zeichnen des Listenfelds mit Combobox-Elementen wenn Message.Msg = WM_CTLCOLORLISTBOX dann Start GetWindowRect (ComboBox3.Handle, cr); // Listbox Rechteck GetWindowRect (Message.LParam, lbr); // verschiebe es nach links, um mit dem rechten Rand übereinzustimmen wenn cr.Right lbr.Right dann MoveWindow (Message.LParam, lbr.Left- (lbr.Right-clbr.Right), lbr.Top, lbr.Right-lbr.Left, lbr.Bottom-lbr.Top, True); Ende sonst ComboBox3WindowProcORIGINAL (Nachricht); Ende; 

Wenn die Meldung, die unser Kombinationsfeld empfängt, WM_CTLCOLORLISTBOX lautet, erhalten wir das Rechteck des Fensters und das Rechteck des anzuzeigenden Listenfelds (GetWindowRect). Wenn das Listenfeld mehr rechts angezeigt wird, verschieben wir es nach links, sodass der rechte Rand von Kombinationsfeld und Listenfeld identisch ist. So einfach ist das :)

Wenn die Nachricht nicht WM_CTLCOLORLISTBOX ist, rufen wir einfach die ursprüngliche Nachrichtenbehandlungsprozedur für das Kombinationsfeld auf (ComboBox3WindowProcORIGINAL)..

Schließlich kann all dies funktionieren, wenn wir es richtig eingestellt haben (in der OnCreate-Ereignisbehandlungsroutine für das Formular):

 // Formulars OnCreate Verfahren TForm.FormCreate (Absender: TObject); Start ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // Modifiziertes / benutzerdefiniertes WindowProc für ComboBox3 anhängen ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; Ende; 

Wo in der Erklärung des Formulars haben wir (gesamt):

 Art TForm = Klasse(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox; Verfahren FormCreate (Absender: TObject); Privat ComboBox3WindowProcORIGINAL: TWndMethod; Verfahren ComboBox3WindowProc (var Nachricht: TMessage); Öffentlichkeit Öffentliche Erklärungen Ende; 

Und das ist es. Alles erledigt :)