已发布的 TStrings-属性 未加载自定义控件

published TStrings-property is not loaded for custom control

我写了一个类似TListBox的控件(类似于Doctor Bob's SpeedBox)。

它运行良好,除了一个问题:分配给 属性 Items 的字符串在启动时没有加载到 TListBox 字段中。我发现,我的程序 SetItem 在创建时没有被调用,因为组件 reader 分配字符串 TStrings.Add.

控件的源代码:

unit HKS.Controls.FilterListBox;

interface

uses
  System.Classes, Vcl.Controls, Vcl.StdCtrls;

type
  THKSFilterListBox = class(TWinControl)
  strict private
    FEdit: TEdit;
    FItems: TStrings;
    FListBox: TListBox;
    procedure SetItems(const Value: TStrings);
    procedure ReInitListBoxItems;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  published
    property Items: TStrings read FItems write SetItems;
  end;

procedure Register;

implementation

uses
  System.SysUtils, Vcl.Graphics, Winapi.Windows;

procedure Register;
begin
  RegisterComponents('HKS', [THKSFilterListBox]);
end;

{ THKSFilterListBox }

constructor THKSFilterListBox.Create(AOwner: TComponent);
begin
  inherited;

  FItems := TStringList.Create;

  FEdit  := TEdit.Create(Self);
  FEdit.Parent    := Self;

  FListBox := TListBox.Create(Self);
  FListBox.Parent := Self;

  ReInitListBoxItems; // has no effect since data is not loaded yet
end;

destructor THKSFilterListBox.Destroy;
begin
  FreeAndNil(FListBox);
  FreeAndNil(FEdit);
  FreeAndNil(FItems);
  inherited;
end;

procedure THKSFilterListBox.ReInitListBoxItems;
var
  LFilterText: String;
begin
  LFilterText := AnsiUpperCase(Trim(FEdit.Text));

  FListBox.Items.BeginUpdate;
  try
    if LFilterText <> '' then
    begin
      // some filter routine
    end else
      FListBox.Items.Assign(FItems);
  finally
    FListBox.Items.EndUpdate;
  end;
end;

procedure THKSFilterListBox.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
const
  cEditHeightAddon = 12;
  cMargin          =  2;
var
  LListBoxTop: Integer;
begin
  inherited;
  FEdit.SetBounds(0, 0, Self.Width, Abs(Font.Height) + cEditHeightAddon);
  LListBoxTop := FEdit.BoundsRect.Bottom + cMargin;
  FListBox.SetBounds(0, LListBoxTop, Self.Width, Self.Height - LListBoxTop);
end;

// is not called on startup because items are added one by one with "TStrings.Add"
procedure THKSFilterListBox.SetItems(const Value: TStrings);
begin
  FItems.Assign(Value);
  ReInitListBoxItems;
end;

end.

我需要自己的 Items 实例,因为并非所有项目都会显示,具体取决于 FEdit.Text.

中的过滤器字符串

从 dfm 加载属性后,是否有任何方法可以调用 ReInitListBoxItems

Is there any way to call ReInitListBoxItems after properties have been loaded from dfm?

覆盖组件的 Loaded 方法。

Initializes the component after the form file has been read into memory.

Do not call the protected Loaded method. The streaming system calls this method after it loads the component's form from a stream.

When the streaming system loads a form or data module from its form file, it first constructs the form component by calling its constructor, then reads its property values from the form file. After reading all the property values for all the components, the streaming system calls the Loaded methods of each component in the order the components were created. This gives the components a chance to initialize any data that depends on the values of other components or other parts of itself.

type
  THKSFilterListBox = class(TWinControl)
    ...
  protected
    procedure Loaded; override;
    ...
  end;

procedure THKSFilterListBox.Loaded;
begin
  inherited;
  ReInitListBoxItems;
end;