【发布时间】:2022-11-04 03:21:33
【问题描述】:
使用 StackOverflow 中的一些答案,我在 Delphi 中创建了一个可搜索的 TComboBox。当您将其直接添加到表单时它工作正常,但一旦您将其添加到 TPanel 就会中断,我似乎无法弄清楚为什么。
直接在表格上:
面板内部:
这是组件的代码:
unit uSmartCombo;
interface
uses
Vcl.StdCtrls, Classes, Winapi.Messages, Controls;
type
TSmartComboBox = class(TComboBox)
private
FStoredItems: TStringList;
procedure FilterItems;
procedure CNCommand(var AMessage: TWMCommand); message CN_COMMAND;
procedure RedefineCombo;
procedure SetStoredItems(const Value: TStringList);
procedure StoredItemsChange(Sender: TObject);
protected
procedure KeyPress(var Key: Char); override;
procedure CloseUp; override;
procedure Loaded; override;
procedure DoExit; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property StoredItems: TStringList read FStoredItems write SetStoredItems;
end;
procedure Register;
implementation
uses
SysUtils, Winapi.Windows, Vcl.Forms;
procedure Register;
begin
RegisterComponents('Standard', [TSmartComboBox]);
end;
constructor TSmartComboBox.Create(AOwner: TComponent);
begin
inherited;
FStoredItems := TStringList.Create;
FStoredItems.OnChange := StoredItemsChange;
end;
destructor TSmartComboBox.Destroy;
begin
FStoredItems.Free;
inherited;
end;
procedure TSmartComboBox.DoExit;
begin
inherited;
RedefineCombo;
end;
procedure TSmartComboBox.Loaded;
var LParent: TWinControl;
LPoint: TPoint;
begin
inherited;
if Items.Count > 0 then
FStoredItems.Assign(Items);
AutoComplete := False;
Style := csDropDownList;
// The ComboBox doesn't behave properly if the parent is not the form.
// Workaround to pull it from any parenting
//if not (Parent is TForm) then
//begin
// LParent := Parent;
// while (not (LParent is TForm)) and Assigned(LParent) do
// LParent := LParent.Parent;
// LPoint := ClientToParent(Point(0,0), LParent);
// Parent := LParent;
// Left := LPoint.X;
// Top := LPoint.Y;
// BringToFront;
//end;
end;
procedure TSmartComboBox.RedefineCombo;
var S: String;
begin
if Style = csDropDown then
begin
if ItemIndex <> -1 then
S := Items[ItemIndex];
Style := csDropDownList;
Items.Assign(FStoredItems);
if S <> '' then
ItemIndex := Items.IndexOf(S);
end;
end;
procedure TSmartComboBox.SetStoredItems(const Value: TStringList);
begin
if Assigned(FStoredItems) then
FStoredItems.Assign(Value)
else
FStoredItems := Value;
end;
procedure TSmartComboBox.StoredItemsChange(Sender: TObject);
begin
if Assigned(FStoredItems) then
begin
RedefineCombo;
Items.Assign(FStoredItems);
end;
end;
procedure TSmartComboBox.KeyPress(var Key: Char);
begin
if CharInSet(Key, ['a'..'z']) and not (Style = csDropDown) then
begin
DroppedDown := False;
Style := csDropDown;
end;
inherited;
if not (Ord(Key) in [13,27]) then
DroppedDown := True;
end;
procedure TSmartComboBox.CloseUp;
begin
if Style = csDropDown then
RedefineCombo;
inherited;
end;
procedure TSmartComboBox.CNCommand(var AMessage: TWMCommand);
begin
inherited;
if (AMessage.Ctl = Handle) and (AMessage.NotifyCode = CBN_EDITUPDATE) then
FilterItems;
end;
procedure TSmartComboBox.FilterItems;
var I: Integer;
Selection: TSelection;
begin
SendMessage(Handle, CB_GETEDITSEL, WPARAM(@Selection.StartPos), LPARAM(@Selection.EndPos));
Items.BeginUpdate;
Try
if Text <> '' then
begin
Items.Clear;
for I := 0 to FStoredItems.Count - 1 do
if (Pos(Uppercase(Text), Uppercase(FStoredItems[I])) > 0) then
Items.Add(FStoredItems[I]);
end
else
Items.Assign(FStoredItems);
Finally
Items.EndUpdate;
End;
SendMessage(Handle, CB_SETEDITSEL, 0, MakeLParam(Selection.StartPos, Selection.EndPos));
end;
end.
任何帮助我如何继续弄清楚为什么会发生这种情况将不胜感激!
编辑1:
在做了一些额外的调试之后,我注意到发送到 ComboBox 的消息与面板内的消息不同。
CBN_EDITUPDATE 永远不会发送,就像 cmets 中提到的 @Sherlock70 一样,这使得 FilterItems 过程永远不会触发。
我还注意到在面板内使用 ComboBox 后表单的行为很奇怪,有时会冻结甚至没有响应,就像它卡在一个循环中一样。
这种不可预测的行为使我放弃了这种方法,我可能会采取另一种方法来创建“可搜索的 ComboBox”。
如果有人想弄清楚甚至可能使用该组件,则将问题悬而未决。
【问题讨论】:
-
为什么“直接”版本的列表之后仍然有 3 项而不是 2 项?空项目从何而来?
-
@AmigoJack 只是下拉列表高度计算不正确,它只有 2 个项目。
-
你试过调试吗?在你的
FilterItems例程中设置一个断点,并检查它何时被调用以及它对于想要的(TForm)和不需要的(TPanel)行为的行为。如果您不确定为什么这些不同,请发布您找到的其他信息。 -
带有这些消息和句柄的东西是不对的。我的第一个尝试是确保消息真正由 ComboBox 发送和读取。但这并没有改变什么。我注意到父级组合从未收到 EDITUPDATE 命令,所以我的猜测是面板正在干扰。
标签: delphi delphi-xe2