【问题标题】:published TStrings-property is not loaded for custom control未为自定义控件加载已发布的 TStrings 属性
【发布时间】:2015-09-15 15:15:06
【问题描述】:

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

它运行良好,除了一个问题:分配给属性Items 的字符串在启动时未加载到TListBox 字段中。我发现,我的过程 SetItem 在创建时没有被调用,因为组件读取器使用 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 吗?

【问题讨论】:

    标签: delphi custom-controls deserialization


    【解决方案1】:

    从 dfm 加载属性后,有什么方法可以调用 ReInitListBoxItems?

    覆盖组件的Loaded 方法。

    在表单文件被读入后初始化组件 记忆。

    不要调用受保护的 Loaded 方法。流系统调用 从流中加载组件的表单后的此方法。

    当流系统从其表单加载表单或数据模块时 文件,它首先通过调用它的 构造函数,然后从表单文件中读取其属性值。后 读取所有组件的所有属性值,流式传输 系统按顺序调用每个组件的Loaded方法 创建了组件。这使组件有机会 初始化依赖于其他组件的值的任何数据或 自身的其他部分。

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

    【讨论】:

    • 您还应该将OnChange 事件处理程序分配给FItems,甚至从TStrings 派生一个新类并覆盖其虚方法,而不是使用TStringList。无论哪种方式,这将允许您的组件在加载组件后在运行时对代码中的Items 属性的更改做出反应。例如,HKSFilterListBox1.Items.Add('...') 也不会触发 SetItems()。因此,您需要检测添加内容,以便相应地更新 ListBox。
    • 很好的答案,@David,非常有用的评论,@Remy!我搜索了 Loaded 之类的东西,但是,关于 Remy 的评论,我现在设置了 OnChange 事件处理程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多