TComboBox Компонент сочетает в себе поле редактирования с прокручиваемым списком выбора. Пользователи могут выбрать элемент из списка или ввести непосредственно в поле редактирования.
Раскрывающийся список
Когда поле со списком находится в выпадающем состоянии, Windows отображает тип элемента управления в виде списка для отображения элементов поля со списком для выбора.
Свойство DropDownCount указывает максимальное количество элементов, отображаемых в раскрывающемся списке.
ширина выпадающего списка по умолчанию будет равняться ширине поля со списком.
Когда длина (строки) элементов превышает ширину поля со списком, элементы отображаются как обрезанные!
TComboBox не предоставляет способ установить ширину раскрывающегося списка :(
Исправление ширины выпадающего списка ComboBox
Мы можем установить ширину выпадающего списка, отправив специальный Сообщение Windows в поле со списком. Сообщение CB_SETDROPPEDWIDTH и отправляет минимально допустимую ширину в пикселях списка со списком.
Чтобы жестко закодировать размер выпадающего списка, скажем, до 200 пикселей, вы можете сделать:
SendMessage (theComboBox. Дескриптор, CB_SETDROPPEDWIDTH, 200, 0);
Это нормально, только если вы уверены, что все ваши theComboBox. Элементы не длиннее 200 пикселей (при рисовании).
Чтобы у нас всегда был достаточно широкий раскрывающийся список, мы можем рассчитать необходимую ширину.
Вот функция, чтобы получить необходимую ширину выпадающего списка и установить ее:
процедура ComboBox_AutoWidth (Const ComboBox: TCombobox); Const
HORIZONTAL_PADDING = 4; вар
itemsFullWidth: целое число; idx: целое число; itemWidth: целое число; начать
itemsFullWidth: = 0; // получаем максимальное количество элементов в выпадающем состоянииза idx: = 0 в -1 + theComboBox. Предметы. подсчитывать делатьначать
itemWidth: = theComboBox. Холст. TextWidth (theComboBox. Пункты [IDX]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if (itemWidth> itemsFullWidth) тогда itemsFullWidth: = itemWidth; конец; // установить ширину выпадающего меню, если необходимоесли (itemsFullWidth> theComboBox. Ширина) тогда. начать// проверяем, будет ли полоса прокруткиесли theComboBox. DropDownCount тогда
itemsFullWidth: = itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL); SendMessage (theComboBox. Дескриптор, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); конец; конец;
Ширина самой длинной строки используется для ширины раскрывающегося списка.
Когда вызывать ComboBox_AutoWidth?
Если вы предварительно заполните список элементов (во время разработки или при создании формы), вы можете вызвать процедуру ComboBox_AutoWidth внутри формы OnCreate обработчик события.
Если вы динамически изменяете список элементов поля со списком, вы можете вызвать процедуру ComboBox_AutoWidth внутри OnDropDown обработчик события - происходит, когда пользователь открывает раскрывающийся список.
Тест
Для теста у нас есть 3 поля со списком в форме. У всех есть элементы с более широким текстом, чем фактическая ширина поля со списком. Третье поле со списком размещается возле правого края границы формы.
Свойство Items для этого примера предварительно заполнено - мы вызываем наш ComboBox_AutoWidth в обработчике события OnCreate для формы:
// Форма OnCreateпроцедура ТГогт. 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 для комбинированного списка правого края решит проблему.
Всемогущий WindowProc
Каждый элемент управления VCL предоставляет свойство WindowProc - процедуру, которая отвечает на сообщения, отправленные в элемент управления. Мы можем использовать свойство WindowProc для временной замены или создания подкласса оконной процедуры элемента управления.
Вот наш модифицированный WindowProc для Combobox3 (тот, что у правого края):
// модифицированный ComboBox3 WindowProcпроцедура ТГогт. ComboBox3WindowProc (вар Сообщение: TMessage); вар
cr, lbr: TRect; начать// рисуем список со списком
если сообщение. Msg = WM_CTLCOLORLISTBOX тогда. начать
GetWindowRect (ComboBox3.Handle, cr); // прямоугольник списка
GetWindowRect (Сообщение. LParam, lbr); // переместить влево, чтобы соответствовать правой границеесли кр. Правый Правильно тогда
MoveWindow (Сообщение. LParam, lbr. Лево- (LBR. Правая clbr. Справа), lbr. Верхняя часть Право-LBR. Слева, lbr. Bottom-LBR. Вершина, правда); конецеще
ComboBox3WindowProcORIGINAL (Message); конец;
Если сообщение, которое получает наше поле со списком, является WM_CTLCOLORLISTBOX, мы получаем прямоугольник его окна, мы также получаем прямоугольник списка, который будет отображаться (GetWindowRect). Если окажется, что поле со списком появилось бы правее - мы переместим его влево, чтобы поле со списком и правая граница списка были одинаковыми. Так просто, как это :)
Если сообщение не WM_CTLCOLORLISTBOX, мы просто вызываем оригинальную процедуру обработки сообщения для поля со списком (ComboBox3WindowProcORIGINAL).
Наконец, все это может работать, если мы установили его правильно (в обработчике события OnCreate для формы):
// Форма OnCreateпроцедура ТГогт. FormCreate (Отправитель: TObject); начать
ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth (ComboBox3); // прикрепляем измененный / пользовательский WindowProc для ComboBox3
ComboBox3WindowProcORIGINAL: = ComboBox3.WindowProc; ComboBox3.WindowProc: = ComboBox3WindowProc; конец;
Где в декларации формы мы имеем (весь):
тип
TForm = учебный класс(ТГогт) ComboBox1: TComboBox; ComboBox2: TComboBox; ComboBox3: TComboBox;процедура FormCreate (Отправитель: TObject); частный
ComboBox3WindowProcORIGINAL: TWndMethod; процедура ComboBox3WindowProc (вар Сообщение: TMessage); общественности{Публичные декларации}конец;
Вот и все. Все обработано :)