gpt4 book ai didi

delphi - TComboBox - 如何在下拉列表下拉时调整其高度?

转载 作者:行者123 更新时间:2023-12-03 14:48:19 27 4
gpt4 key购买 nike

我受到这个问题的启发:How to make a combo box with full-text search autocomplete support

answer工作得很好,但我想调整建议列表高度/DropDownCount当用户键入文本时,列表已经下拉。

这是一个稍作修改的 MCVE - 当用户开始输入时,下拉列表将下拉,并且我还修复了下拉列表时鼠标光标效果未设置为箭头的问题:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, StrUtils, ExtCtrls;

type
TComboBox = class(StdCtrls.TComboBox)
private
FStoredItems: TStringList;
FOldCursor: TCursor; // NEW !!!
procedure FilterItems;
procedure StoredItemsChange(Sender: TObject);
procedure SetStoredItems(const Value: TStringList);
procedure CNCommand(var AMessage: TWMCommand); message CN_COMMAND;
procedure AdjustDropDownHeight; // NEW !!!
protected
// NEW !!!
procedure KeyPress(var Key: Char); override;
procedure DropDown; override;
procedure CloseUp; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property StoredItems: TStringList read FStoredItems write SetStoredItems;
end;

type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

constructor TComboBox.Create(AOwner: TComponent);
begin
inherited;
AutoComplete := False;
FStoredItems := TStringList.Create;
FStoredItems.OnChange := StoredItemsChange;
end;

destructor TComboBox.Destroy;
begin
FStoredItems.Free;
inherited;
end;

procedure TComboBox.CNCommand(var AMessage: TWMCommand);
begin
// we have to process everything from our ancestor
inherited;
// if we received the CBN_EDITUPDATE notification
if AMessage.NotifyCode = CBN_EDITUPDATE then
// fill the items with the matches
FilterItems;
end;

procedure TComboBox.FilterItems;
var
I: Integer;
Selection: TSelection;
begin
// store the current combo edit selection
SendMessage(Handle, CB_GETEDITSEL, WPARAM(@Selection.StartPos),
LPARAM(@Selection.EndPos));
// begin with the items update
Items.BeginUpdate;
try
// if the combo edit is not empty, then clear the items
// and search through the FStoredItems
if Text <> '' then
begin
// clear all items
Items.Clear;
// iterate through all of them
for I := 0 to FStoredItems.Count - 1 do
// check if the current one contains the text in edit
if ContainsText(FStoredItems[I], Text) then
// and if so, then add it to the items
Items.Add(FStoredItems[I]);
end
// else the combo edit is empty
else
// so then we'll use all what we have in the FStoredItems
Items.Assign(FStoredItems)
finally
// finish the items update
Items.EndUpdate;
end;
// and restore the last combo edit selection
SendMessage(Handle, CB_SETEDITSEL, 0, MakeLParam(Selection.StartPos,
Selection.EndPos));

// NEW !!! - if the list is dropped down adjust the list height
if DroppedDown then
AdjustDropDownHeight;
end;

procedure TComboBox.StoredItemsChange(Sender: TObject);
begin
if Assigned(FStoredItems) then
FilterItems;
end;

procedure TComboBox.SetStoredItems(const Value: TStringList);
begin
if Assigned(FStoredItems) then
FStoredItems.Assign(Value)
else
FStoredItems := Value;
end;

// NEW !!!
procedure TComboBox.KeyPress(var Key: Char);
begin
inherited;
if not (Ord(Key) in [VK_RETURN, VK_ESCAPE]) then
begin
if (Items.Count <> 0) and not DroppedDown then
// SendMessage(Handle, CB_SHOWDROPDOWN, 1, 0);
DroppedDown := True;
end;
end;

procedure TComboBox.DropDown;
begin
FOldCursor := Screen.Cursor;
Screen.Cursor := crArrow;
inherited;
end;

procedure TComboBox.CloseUp;
begin
Screen.Cursor := FOldCursor;
inherited;
end;

procedure TComboBox.AdjustDropDownHeight;
var
Count: Integer;
begin
Count := Items.Count;
SetWindowPos(FDropHandle, 0, 0, 0, Width, ItemHeight * Count +
Height + 2, SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOREDRAW or
SWP_HIDEWINDOW);
SetWindowPos(FDropHandle, 0, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or
SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOREDRAW or SWP_SHOWWINDOW);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
ComboBox: TComboBox;
begin
// here's one combo created dynamically
ComboBox := TComboBox.Create(Self);
ComboBox.Parent := Self;
ComboBox.Left := 10;
ComboBox.Top := 10;

// here's how to fill the StoredItems
ComboBox.StoredItems.BeginUpdate;
try
ComboBox.StoredItems.Add('Mr John Brown');
ComboBox.StoredItems.Add('Mrs Amanda Brown');
ComboBox.StoredItems.Add('Mr Brian Jones');
ComboBox.StoredItems.Add('Mrs Samantha Smith');
finally
ComboBox.StoredItems.EndUpdate;
end;
end;

end.

我添加了AdjustDropDownHeight (受到 TCustomCombo.AdjustDropDown 的启发)在 FilterItems 中方法,但似乎没有按预期工作。窗口隐藏,高度没有根据TComboBox中的实际项目进行调整当它被放下时。

看起来像FDropHandle没有响应(或处理)SetWindowPos(FDropHandle, ...AdjustDropDownHeight方法。

这个问题可以解决吗?如何根据实际元素调整下拉时的高度?

<小时/>

编辑:设置DropDownCount := Items.Count (正如答案中所建议的)是我尝试的第一件事(它设置了最大项目数)。但是,在键入文本时,下拉窗口不会更改其高度(虽然它已经下拉)。 SetDropDownCount setter 只需设置 FDropDownCount := Value 。这将设置下次下拉列表被删除时的下拉计数/高度。我需要在它被下拉时改变。希望现在更清楚了。

(也许较新的 Delphi 版本有不同的 SetDropDownCount setter?)

<小时/>

为了更好地展示我想要的东西:

用户类型 Mr

enter image description here

然后Mrs (列表高度已调整)

enter image description here

然后用户按退格键到 Mr (列表高度再次调整):

enter image description here

<小时/>

编辑2:@Dsm 是正确的,给了我正确的方向。较新的 Delphi 版本 SetDropDownCount setter 发送额外的 CB_SETMINVISIBLE消息,这按预期工作:

procedure TCustomCombo.SetDropDownCount(const Value: Integer);
begin
if Value <> FDropDownCount then
begin
FDropDownCount := Value;
if HandleAllocated and CheckWin32Version(5, 1) and ThemeServices.ThemesEnabled then
SendMessage(Handle, CB_SETMINVISIBLE, WPARAM(FDropDownCount), 0);
end;
end;

对于旧版本定义:

const
CBM_FIRST = $1700;
CB_SETMINVISIBLE = CBM_FIRST + 1;

最佳答案

其实就这么简单

procedure TComboBox.AdjustDropDownHeight;
begin
DropDownCount := Items.Count;
end;

我使用您的 MCVE 进行了测试,效果很好。

关于delphi - TComboBox - 如何在下拉列表下拉时调整其高度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44070905/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com