Delphi 财产设定者似乎从未在拉扎勒斯开火?
概述 我有一个Delphi 财产设定者似乎从未在拉扎勒斯开火?,delphi,lazarus,Delphi,Lazarus,概述 我有一个TCustomControl我在Lazarus工作,在这个类之外,我有一个单独的TPersistent类,它将用于某些属性 从TCustomControl发布的TPersistent类应在对象检查器中显示为子属性,因为我不希望从顶层显示某些属性,基本上这是将一些属性放入TCustomControl中自己的组中 本守则的结构如下: type TMyControlHeaderOptions = class(TPersistent) private FOnChange:
TCustomControl
我在Lazarus工作,在这个类之外,我有一个单独的TPersistent
类,它将用于某些属性
从TCustomControl
发布的TPersistent
类应在对象检查器中显示为子属性,因为我不希望从顶层显示某些属性,基本上这是将一些属性放入TCustomControl
中自己的组中
本守则的结构如下:
type
TMyControlHeaderOptions = class(TPersistent)
private
FOnChange: TNotifyEvent;
FHeight: Integer;
FVisible: Boolean;
procedure SetHeight(const Value: Integer);
procedure SetVisible(const Value: Boolean);
protected
procedure Changed;
public
constructor Create(AOwner: TComponent); virtual;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
published
property Height: Integer read FHeight write SetHeight default 20;
property Visible: Boolean read FVisible write SetVisible default True;
end;
TMyControl = class(TCustomControl)
private
FHeaderOptions: TMyControlHeaderOptions;
procedure SetHeaderOptions(const Value: TMyControlHeaderOptions);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Align;
property BorderStyle default bsSingle;
property HeaderOptions: TMyControlHeaderOptions read FHeaderOptions write SetHeaderOptions;
end;
以下是TMyControlHeaderOptions
的代码:
constructor TMyControlHeaderOptions.Create(AOwner: TComponent);
begin
FHeight := 20;
FVisible := True;
end;
destructor TMyControlHeaderOptions.Destroy;
begin
inherited Destroy;
end;
// this method never fires (see TMyControl.SetHeaderOptions)
procedure TMyControlHeaderOptions.Assign(Source: TPersistent);
begin
if (Source is TMyControlHeaderOptions) then
begin
FHeight := (Source as TMyControlHeaderOptions).Height;
FVisible := (Source as TMyControlHeaderOptions).Visible;
end
else
inherited Assign(Source);
end;
procedure TMyControlHeaderOptions.Changed;
begin
if Assigned(FOnChange) then
begin
FOnChange(Self);
end;
end;
procedure TMyControlHeaderOptions.SetHeight(const Value: Integer);
begin
if Value <> FHeight then
begin
FHeight := Value;
Changed;
end;
end;
procedure TMyControlHeaderOptions.SetVisible(const Value: Boolean);
begin
if Value <> FVisible then
begin
FVisible := Value;
Changed;
end;
end;
问题
属性HeaderOptions
从未在设计时或运行时触发或被激发,我只是不明白或不明白为什么不触发或被激发?从上面代码中包含的注释可以看出,SetHeaderOptions
似乎根本没有做任何事情,它从不响应在设计时或运行时所做的更改
我没有安装Delphi进行比较或测试,但代码取自我以前使用过的自定义控件,我非常确定它应该可以工作,我似乎没有遗漏任何可以看到的内容。在这一点上,我唯一的假设是拉扎勒斯和德尔菲的差异,所以问题可能在于拉扎勒斯
问题
所以我的问题是,为什么属性设置者头选项
永远不会被解雇,如何确保它被解雇
我感觉到一些简单或明显的东西,但我就是搞不清楚它是什么。当您更改此
t持久
中的属性时,它会触发该特定属性的属性设置程序。它不应该调用TPersistent
本身的setter。只有在两种情况下才会出现这种情况:a)在创建时将DFM导入,或b)手动将新值分配给实际的t持久的
。如果要在任何属性发生更改时捕获,则需要单独捕获每个属性,可能会触发一个OnChange
notify事件,该事件将反馈给其所有者。这实际上就是TFont
或TStrings
的工作方式
看看一些内置类,比如
TFont
和TStrings
——它们使用名为OnChange
的TNotifyEvent
来处理这些更改。我仍然不明白为什么这在Lazarus中不起作用,因为我几乎可以肯定它在Delphi中起作用
与此同时,我设法想出了一个解决办法:
TMyControl = class(TCustomControl)
private
FHeaderOptions: TMyControlHeaderOptions;
procedure HeaderOptionsChanged(Sender: TObject); // added this line
procedure SetHeaderOptions(const Value: TMyControlHeaderOptions); // removed this procedure
published
property Align;
property BorderStyle default bsSingle;
property HeaderOptions: TMyControlHeaderOptions read FHeaderOptions write FHeaderOptions; // changed this
end;
然后在构造函数中添加了以下内容:
constructor TMyControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FHeaderOptions := TMyControlHeaderOptions.Create(Self);
FHeaderOptions.OnChange := @HeaderOptionsChanged; // added this line
Self.ControlStyle := Self.ControlStyle + [csAcceptsControls];
Self.BorderStyle := bsSingle;
Self.Height := 200;
Self.Width := 250;
end;
新磁头选项更改的代码程序:
procedure TMyControl.HeaderOptionsChanged(Sender: TObject);
begin
// header options changed
Invalidate;
end;
我想知道OP是否真的询问了类似的情况:谢谢你的反馈,我会看看是否有其他方法来捕捉变化。我知道在Delphi中我是这样做的,这有点奇怪。例如,在TMyControl的地方,它可以工作。SetHeaderOptions
会启动,但在Lazarus中它似乎什么都不做。@Craig,在Delphi中也是这样。事实上,我从未使用过Lazarus,但它肯定是一样的。这就是为什么我感到困惑的原因,我知道从技术上讲Lazarus不是Delphi的完全复制品,因此应该被视为它自己的,但它仍然使用几乎相同的Pascal OOP语法。所以,如果不是Lazarus,那么它一定是我的代码,但我确信我所做的与我通常在Delphi中所做的没有什么不同。@Craig,这两种情况下都无法工作。实际的TPersistent
本身并不关心其成员做什么。这取决于你决定如何反馈给它的主人。你过去的经验一定有一些你忘记的额外代码。我个人很讨厌t持久的的属性设置程序在其成员发生更改时被触发。属性设置程序在您设置该属性时触发,您永远不会将任何内容分配给“HeaderOptions”。@SertacAkyuz,行FHeaderOptions.assign(Value)TMyControl.SetHeaderOptions
过程中的code>应该调用TMyControlHeaderOptions
类中被重写的Assign
。属性是HeaderOptions,而不是FHeaderOptions。这不是一种变通方法,正如我在回答中解释的那样,它应该是这样设计的。但是,您引入了两个新问题。a) 为什么要使用@
?那是不必要的。b)不应该放弃属性设置器,应该保留它并使用FHeaderOptions.Assign(Value)代码>。像TFont
和TStrings
这样的东西正是因为这个原因才这样工作的。@Jerrydoge在Lazarus/FPC中你需要使用“@”符号操作符;)我删除了FHeaderOptions.Assign(Value)代码>因为它仍然不会开火。我明白了。我使用Assign()。在某些情况下,这可能会导致内存泄漏。我几乎可以肯定它在Delphi中确实有效。不。你搞错了。此外,这里概述的变化是完全错误的。现在泄漏TMyControlHeaderOptions
的实例@杰瑞说得对,你应该接受他的回答-1@DavidHeffernan在哪里泄漏TmyControlHeaderOptions的实例?查看原始代码,这只是的一个修改版本,析构函数在那里释放FHeaderOptions
。
procedure TMyControl.HeaderOptionsChanged(Sender: TObject);
begin
// header options changed
Invalidate;
end;