Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 财产设定者似乎从未在拉扎勒斯开火?_Delphi_Lazarus - Fatal编程技术网

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;