已发布的 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;
我写了一个类似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;