Оразмеряване на падащата ширина на ComboBox

Най- TComboBox компонент комбинира поле за редактиране със превъртащ се списък за „избор“. Потребителите могат да изберат елемент от списъка или да го напишат директно в поле за редактиране.

Падащ списък

Когато комбинирана кутия е в паднало състояние, Windows изготвя тип поле за управление, за да се покажат елементите от полето за избор.

Най- Свойство DropDownCount указва максималния брой елементи, показани в падащия списък.

Най- ширина на падащия списък по подразбиране би била равна на ширината на полето за комбиниране.

Когато дължината (на низ) от елементите надвишава ширината на полето за съхранение, елементите се показват като отрязани!

TComboBox не предоставя начин да зададете ширината на падащия си списък :(

Фиксиране на ширината на падащия списък ComboBox

Можем да зададем ширината на падащия списък, като изпратим специален Съобщение за Windows до комбинираното поле. Съобщението е CB_SETDROPPEDWIDTH и изпраща минималната допустима ширина, в пиксели, на списъчното поле на комбинирано поле.

instagram viewer

За да кодирате твърдо размера на падащия списък до, да речем, 200 пиксела, можете да направите:


Изпращане на съобщение (theComboBox. Дръжка, CB_SETDROPPEDWIDTH, 200, 0); 

Това е добре само ако сте сигурни, че всичките ви theComboBox. Елементите не са по-дълги от 200 px (когато са изтеглени).

За да гарантираме, че дисплеят на падащия списък винаги е достатъчно широк, можем да изчислим необходимата ширина.

Ето функция, за да получите необходимата ширина на падащия списък и да го зададете:

процедура ComboBox_AutoWidth (конст theComboBox: TCombobox); конст
HORIZONTAL_PADDING = 4; Var
itemsFullWidth: цяло число; idx: цяло число; itemWidth: цяло число; започвам
itemsFullWidth: = 0; // получи максимално необходимото за елементите в падащо състояниеза idx: = 0 да се -1 + theComboBox. Предмети. Броя правязапочвам
itemWidth: = theComboBox. Платно. TextWidth (theComboBox. Артикули [IDX]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); ако (itemWidth> itemsFullWidth) тогава itemsFullWidth: = itemWidth; край; // задайте ширината на падащото меню, ако е необходимоако (itemsFullWidth> theComboBox. Ширина) тогава. започвам// проверете дали ще има лента за превъртанеако theComboBox. DropDownCount тогава
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); Изпращане на съобщение (theComboBox. Дръжка, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); край; край; 

Ширината на най-дългия низ се използва за ширината на падащия списък.

Кога да се обадя на ComboBox_AutoWidth?
Ако предварително попълните списъка с елементи (по време на проектиране или при създаване на формуляра), можете да се обадите на процедурата ComboBox_AutoWidth вътре в формуляра OnCreate обработващ събитията.

Ако динамично променяте списъка с елементи на полето за комбо, можете да се обадите на процедурата ComboBox_AutoWidth вътре в OnDropDown обработчик на събития - възниква, когато потребителят отвори падащия списък.

Тест
За тест имаме 3 комбинирани кутии на формуляр. Всички имат елементи с техния текст по-широк от действителната ширина на полето за комбиниране. Третото комбинирано поле се поставя близо до десния ръб на рамката на формата.

Свойството „елементи“, например, е предварително попълнено - наричаме нашия ComboBox_AutoWidth в обработващия събитията OnCreate за формата:

// OnCreate на формапроцедура TForm. FormCreate (подател: TObject); започвам
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); край; 

Не сме се обадили на ComboBox_AutoWidth за Combobox1, за да видим разликата!

Имайте предвид, че когато стартирате, падащият списък за Combobox2 ще бъде по-широк от Combobox2.

Целият падащ списък е отрязан за „Положение в близост до десния край“

За Combobox3, който е разположен близо до десния ръб, падащият списък е отрязан.

Изпращането на CB_SETDROPPEDWIDTH винаги ще разширява полето на падащия списък вдясно. Когато комбинираната ви кутия е близо до десния ръб, разширяването на полето със списък вдясно ще доведе до отрязване на дисплея на списъка.

Трябва по някакъв начин да разширим полето на списъка вляво, когато това е така, а не вдясно!

CB_SETDROPPEDWIDTH няма начин да посочи в каква посока (отляво или отдясно) да се разшири полето за списък.

Решение: WM_CTLCOLORLISTBOX

Точно когато трябва да се покаже падащият списък, Windows изпраща съобщението WM_CTLCOLORLISTBOX до родителския прозорец на полето със списък - до комбинираното ни поле.

Възможността да се справи с WM_CTLCOLORLISTBOX за близкия до десния край комбобокс ще реши проблема.

Всемогъщият прозорецProc
Всяка VCL контрола излага свойството WindowProc - процедурата, която отговаря на съобщения, изпратени до контрола. Можем да използваме свойството WindowProc за временно заместване или подкласиране на процедурата на прозореца на контрола.

Ето нашия модифициран WindowProc за Combobox3 (този в близост до десния ръб):

// модифициран ComboBox3 WindowProcпроцедура TForm. ComboBox3WindowProc (Var Съобщение: TMessage); Var
cr, lbr: TRect; започвам// изчертаване на списъка с елементи от полето
ако Съобщение. Msg = WM_CTLCOLORLISTBOX тогава. започвам
GetWindowRect (ComboBox3.Handle, cr); // правоъгълник на списъка
GetWindowRect (Съобщение LParam, lbr); // преместете го наляво, за да съвпада с дясната границаако кр. Право <> lbr. прав тогава
MoveWindow (Съобщение LParam, lbr. За лява (LBR. Десния clbr. Вдясно), lbr. Отгоре, lbr. Десния LBR. Вляво, lbr. Долу-LBR. Нагоре, Вярно); крайоще
ComboBox3WindowProcORIGINAL (ЛС); край; 

Ако съобщението, което получава комбинираната ни кутия, е WM_CTLCOLORLISTBOX, получаваме правоъгълника на прозореца си, получаваме и правоъгълника на списъчното поле (GetWindowRect). Ако се окаже, че полето със списъка ще се появи повече вдясно - ние го преместваме вляво, така че комбинираното поле и полето с дясната граница да е същото. Лесно като това :)

Ако съобщението не е WM_CTLCOLORLISTBOX, ние просто се обаждаме на оригиналната процедура за обработка на съобщения за комбинираното поле (ComboBox3WindowProcORIGINAL).

И накрая, всичко това може да работи, ако сме го задали правилно (в манипулатора на събитията OnCreate за формата):

// OnCreate на формапроцедура TForm. FormCreate (подател: TObject); започвам
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // прикачете модифициран / персонализиран WindowProc за ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; край; 

Къде в декларацията на формуляра имаме (цяла):

Тип
TForm = клас(TForm) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;процедура FormCreate (подател: TObject); частен
ComboBox3WindowProcORIGINAL: TWndMethod; процедура ComboBox3WindowProc (Var Съобщение: TMessage); обществен{Публични декларации}край; 

И това е. Всички се обработват :)