Dimensionierung der ComboBox-Dropdown-Breite

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

Dropdown-Liste

Wenn sich ein Kombinationsfeld im Dropdown-Status befindet, zeichnet Windows ein Steuerelement vom Typ Listenfeld, um Kombinationsfeldelemente zur Auswahl anzuzeigen.

Das DropDownCount-Eigenschaft Gibt die maximale Anzahl von Elementen an, die in der Dropdown-Liste angezeigt werden.

Das Breite der Dropdown-Liste würde standardmäßig der Breite des Kombinationsfelds entsprechen.

Wenn die Länge (einer Zeichenfolge) von Elementen die Breite der Combobox überschreitet, werden die Elemente als Cut-Off angezeigt!

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

Korrigieren der Breite der ComboBox-Dropdown-Liste

Wir können die Breite der Dropdown-Liste festlegen, indem wir ein Special senden Windows-Nachricht zum Kombinationsfeld. Die Nachricht ist CB_SETDROPPEDWIDTH und sendet die minimal zulässige Breite des Listenfelds eines Kombinationsfelds in Pixel.

instagram viewer

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. Gegenstände sind nicht länger als 200 px (wenn gezeichnet).

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

Hier ist eine Funktion, um die erforderliche Breite der Dropdown-Liste abzurufen und festzulegen:

Verfahren ComboBox_AutoWidth (const theComboBox: TCombobox); const
HORIZONTAL_PADDING = 4; var
itemsFullWidth: integer; idx: Ganzzahl; itemWidth: Ganzzahl; Start
itemsFullWidth: = 0; // Holen Sie sich das Maximum, das für die Elemente im Dropdown-Status benötigt wirdzum idx: = 0 zu -1 + theComboBox. Artikel. Anzahl tunStart
itemWidth: = theComboBox. Segeltuch. TextWidth (theComboBox. Items [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) dann itemsFullWidth: = itemWidth; Ende; // gib bei Bedarf die Breite des Dropdowns einwenn (itemsFullWidth> theComboBox. Breite) dann. Start// überprüfe ob es eine Bildlaufleiste geben würdewenn theComboBox. DropDownCount 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 soll ComboBox_AutoWidth aufgerufen werden?
Wenn Sie die Liste der Elemente vorab ausfüllen (zur Entwurfszeit oder beim Erstellen des Formulars), können Sie die Prozedur ComboBox_AutoWidth innerhalb des Formulars aufrufen OnCreate Event-Handler.

Wenn Sie die Liste der Kombinationsfeldelemente dynamisch ändern, können Sie die Prozedur ComboBox_AutoWidth innerhalb von 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. Alle haben Elemente, deren Text breiter als die tatsächliche Breite des Kombinationsfelds ist. Das dritte Kombinationsfeld befindet sich am rechten Rand des Formularrahmens.

In diesem Beispiel ist die Items-Eigenschaft vorab ausgefüllt. Wir rufen unsere ComboBox_AutoWidth im OnCreate-Ereignishandler für das Formular auf:

// OnCreate von FormVerfahren 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 Combobox2.

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

Bei Combobox3, das sich am rechten Rand befindet, wird 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 Sie das Listenfeld weiter nach rechts erweitern, 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

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

Die Möglichkeit, die WM_CTLCOLORLISTBOX für die Combobox am rechten Rand zu handhaben, würde das Problem lösen.

Der allmächtige WindowProc
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 zu unterklassifizieren.

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

// ComboBox3 WindowProc geändertVerfahren TForm. ComboBox3WindowProc (var Nachricht: TMessage); var
cr, lbr: TRect; Start// Zeichnen des Listenfelds mit Combobox-Elementen
wenn Nachricht. Msg = WM_CTLCOLORLISTBOX dann. Start
GetWindowRect (ComboBox3.Handle, cr); // Listenfeld Rechteck
GetWindowRect (Nachricht. LParam, lbr); // Verschiebe es nach links, damit es mit dem rechten Rand übereinstimmtwenn cr. Richtig <> lbr. Richtig dann
MoveWindow (Nachricht. LParam, lbr. Links- (lbr. Rechtskl. Richtig), lbr. Top, lbr. Rechts-lbr. Links, lbr. Bottom-lbr. Oben, wahr); Endesonst
ComboBox3WindowProcORIGINAL (Nachricht); Ende; 

Wenn die Nachricht, 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 das Kombinationsfeld und der rechte Rand des Listenfelds identisch sind. So einfach ist das :)

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

Schließlich kann dies alles funktionieren, wenn wir es richtig eingestellt haben (im OnCreate-Ereignishandler für das Formular):

// OnCreate von FormVerfahren 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 (vollständig):

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 gehandhabt :)