调整下拉框的宽度_调整组合框下拉宽度的大小

调整下拉框的宽度

The TComboBox component combines an edit box with a scrollable "pick" list. Users can select an item from the list or type directly into the edit box.

TComboBox组件将编辑框与可滚动的“选择”列表结合在一起。 用户可以从列表中选择一项,也可以直接在编辑框中键入内容

下拉列表 ( Drop Down List )

When a combo box is in dropped down state Windows draws a list box type of control to display combo box items for selection.

当组合框处于下拉状态时,Windows会绘制列表框的控件类型以显示组合框项目以供选择。

The DropDownCount property specifies the maximum number of items displayed in the drop-down list.

DropDownCount属性指定下拉列表中显示的最大项目数。

The width of the drop-down list would, by default, equal the width of the combo box.

默认情况下, 下拉列表的宽度将等于组合框的宽度。

When the length (of a string) of items exceeds the width of the combobox, the items are displayed as cut-off!

当项目的长度(一串)超过组合框的宽度时,项目显示为截止值!

TComboBox does not provide a way to set the width of its drop-down list :(

TComboBox没有提供一种设置其下拉列表宽度的方法:(

固定ComboBox下拉列表宽度 ( Fixing The ComboBox Drop-Down List Width )

We can set the width of the drop-down list by sending a special Windows message to the combo box. The message is CB_SETDROPPEDWIDTH and sends the minimum allowable width, in pixels, of the list box of a combo box.

我们可以通过向组合框发送特殊的Windows消息来设置下拉列表的宽度。 消息为CB_SETDROPPEDWIDTH,并发送组合框列表框的最小允许宽度(以像素为单位)。

To hardcode the size of the drop-down list to, let's say, 200 pixels, you could do:

要将下拉列表的大小硬编码为200像素,您可以执行以下操作:

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

This is only ok if you are sure all your theComboBox.Items are not longer than 200 px (when drawn).

仅当您确定所有theComboBox.Items的长度不超过200 px(绘制时)时,此方法才可以。

To ensure we always have the drop-down list display enough wide, we can calculate the required width.

为了确保下拉列表始终显示足够的宽度,我们可以计算所需的宽度。

Here's a function to get the required width of the drop-down list and set it:

这是一个函数,用于获取所需的下拉列表宽度并进行设置:

procedure ComboBox_AutoWidth(const theComboBox: TCombobox);
const
HORIZONTAL_PADDING = 4;
var
itemsFullWidth: integer;
idx: integer;
itemWidth: integer;
begin
itemsFullWidth := 0;
// get the max needed with of the items in dropdown state
for idx := 0 to -1 + theComboBox.Items.Count do
begin
itemWidth := theComboBox.Canvas.TextWidth(theComboBox.Items[idx]);
Inc(itemWidth, 2 * HORIZONTAL_PADDING);
if (itemWidth > itemsFullWidth) then itemsFullWidth := itemWidth;
end;
// set the width of drop down if needed
if (itemsFullWidth > theComboBox.Width) then
begin
//check if there would be a scroll bar
if theComboBox.DropDownCount < theComboBox.Items.Count then
itemsFullWidth := itemsFullWidth + GetSystemMetrics(SM_CXVSCROLL);
SendMessage(theComboBox.Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0);
end;
end;

The width of the longest string is used for the width of the drop-down list.

最长字符串的宽度用于下拉列表的宽度。

When to call ComboBox_AutoWidth?If you pre-fill the list of items (at design time or when creating the form) you can call the ComboBox_AutoWidth procedure inside the form's OnCreate event handler.

何时调用ComboBox_AutoWidth? 如果您预先填写了项目列表(在设计时或在创建窗体时),则可以在窗体的OnCreate事件处理程序中调用ComboBox_AutoWidth过程。

If you dynamically change the list of combo box items, you can call the ComboBox_AutoWidth procedure inside the OnDropDown event handler - occurs when the user opens the drop-down list.

如果您动态更改组合框项目的列表,则可以在OnDropDown事件处理程序中调用ComboBox_AutoWidth过程-在用户打开下拉列表时发生。

A TestFor a test, we have 3 combo boxes on a form. All have items with their text more wide than the actual combo box width. The third combo box is placed near the right edge of the form's border.

测试对于一个测试,我们在表单上有3个组合框。 所有项目的文本都比实际组合框的宽度宽。 第三个组合框放置在窗体边框的右边缘附近。

The Items property, for this example, is pre-filled - we call our ComboBox_AutoWidth in the OnCreate event handler for the form:

在此示例中,Items属性是预先填充的-我们在OnCreate事件处理程序中将表单的ComboBox_AutoWidth称为:

//Form's OnCreate
procedure TForm.FormCreate(Sender: TObject);
begin
ComboBox_AutoWidth(ComboBox2);
ComboBox_AutoWidth(ComboBox3);
end;

We've not called ComboBox_AutoWidth for Combobox1 to see the difference!

我们没有为Combobox1调用ComboBox_AutoWidth来看到区别!

Note that, when run, the drop-down list for Combobox2 will be wider than Combobox2.

请注意,运行时,Combobox2的下拉列表将比Combobox2宽。

整个下拉列表被切除为“在右边缘附近放置” ( The Entire Drop-Down List Is Cut Off For "Near Right Edge Placement" )

For Combobox3, the one placed near the right edge, the drop-down list is cut off.

对于Combobox3(位于右边缘附近的那个),下拉列表被切除。

Sending the CB_SETDROPPEDWIDTH will always extend the drop-down list box to the right. When your combobox is near the right edge, extending the list box more to the right would result in the display of the list box being cut off.

发送CB_SETDROPPEDWIDTH将始终将下拉列表框扩展到右侧。 当您的组合框位于右边缘附近时,将列表框向右扩展更多将导致该列表框的显示被切断。

We need to somehow extend the list box to the left when this is the case, not to the right!

在这种情况下,我们需要以某种方式将列表框扩展到左侧,而不是右侧!

The CB_SETDROPPEDWIDTH has no way of specifying to what direction (left or right) to extend the list box.

CB_SETDROPPEDWIDTH无法指定向哪个方向(向左或向右)扩展列表框。

解决方案:WM_CTLCOLORLISTBOX ( Solution: WM_CTLCOLORLISTBOX )

Just when the drop-down list is to be displayed Windows sends the WM_CTLCOLORLISTBOX message to the parent window of a list box - to our combo box.

Windows仅在显示下拉列表时,将WM_CTLCOLORLISTBOX消息发送到列表框的父窗口-到我们的组合框。

Being able to handle the WM_CTLCOLORLISTBOX for the near-right-edge combobox would solve the problem.

能够处理近右边缘组合框的WM_CTLCOLORLISTBOX将解决该问题。

The Almighty WindowProcEach VCL control exposes the WindowProc property - the procedure that responds to messages sent to the control. We can use the WindowProc property to temporarily replace or subclass the window procedure of the control.

万能的WindowProc每个VCL控件都公开WindowProc属性,该属性是响应发送给该控件的消息的过程。 我们可以使用WindowProc属性临时替换或子类化控件的窗口过程。

Here's our modified WindowProc for Combobox3 (the one near the right edge):

这是我们为Combobox3修改的WindowProc(靠近右边缘的那个):

//modified ComboBox3 WindowProc
procedure TForm.ComboBox3WindowProc(var Message: TMessage);
var
cr, lbr: TRect;
begin
//drawing the list box with combobox items
if Message.Msg = WM_CTLCOLORLISTBOX then
begin
GetWindowRect(ComboBox3.Handle, cr);
//list box rectangle
GetWindowRect(Message.LParam, lbr);
//move it to left to match right border
if cr.Right <> lbr.Right then
MoveWindow(Message.LParam,
lbr.Left-(lbr.Right-clbr.Right),
lbr.Top,
lbr.Right-lbr.Left,
lbr.Bottom-lbr.Top,
True);
end
else
ComboBox3WindowProcORIGINAL(Message);
end;

If the message our combo box receives is WM_CTLCOLORLISTBOX we get its window's rectangle, we also get the rectangle of the list box to be displayed (GetWindowRect). If it appears that the list box would appear more to the right - we move it to the left so that combo box and list box right border is the same. As easy as that :)

如果组合框收到的消息是WM_CTLCOLORLISTBOX,则获得其窗口的矩形,我们还获得要显示的列表框的矩形(GetWindowRect)。 如果列表框看起来更向右显示-我们将其向左移动,以便组合框和列表框的右边框相同。 那样简单:)

If the message is not WM_CTLCOLORLISTBOX we simply call the original message handling procedure for the combo box (ComboBox3WindowProcORIGINAL).

如果消息不是WM_CTLCOLORLISTBOX,我们只需调用组合框的原始消息处理过程(ComboBox3WindowProcORIGINAL)。

Finally, all this can work if we have set it correctly (in the OnCreate event handler for the form):

最后,如果我们已正确设置它(在表单的OnCreate事件处理程序中),那么所有这些方法都可以使用:

//Form's OnCreate
procedure TForm.FormCreate(Sender: TObject);
begin
ComboBox_AutoWidth(ComboBox2);
ComboBox_AutoWidth(ComboBox3);
//attach modified/custom WindowProc for ComboBox3
ComboBox3WindowProcORIGINAL := ComboBox3.WindowProc;
ComboBox3.WindowProc := ComboBox3WindowProc;
end;

Where in the form's declaration we have (entire):

在表单的声明中,我们有(整个):

type
TForm = class(TForm)
ComboBox1: TComboBox;
ComboBox2: TComboBox;
ComboBox3: TComboBox;
procedure FormCreate(Sender: TObject);
private
ComboBox3WindowProcORIGINAL : TWndMethod;
procedure ComboBox3WindowProc(var Message: TMessage);
public
{ Public declarations }
end;

And that's it. All handled :)

就是这样。 全部处理:)

翻译自: https://www.thoughtco.com/sizing-the-combobox-drop-down-width-1058301

调整下拉框的宽度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值