delphi 创建组件以更新控件的全局属性

wixjitnu  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(185)

我有一组组件,它们共享一些全局变量来控制公共属性,例如样式特征。
这些当前通过全局类在运行时访问,例如MyCompsSettings(). SomeProperty。
我认为允许用户在设计时配置其中的一些属性可能很有用,所以我将全局类转换为组件,并且因为这些属性需要在MyCompsSettings()和我的TMyCompsSettings组件的示例之间共享,所以我使用全局变量来存储状态,例如。

type
  TMyCompsSettings = class(TComponent)
  private
    function GetBackgroundColor(): TColor;
    procedure SetBackgroundColor(const v: TColor);
    function GetTitleText(): string;
    procedure SetTitleText(const v: string);
  published
    property BackgroundColor: TColor read GetBackgroundColor write SetBackgroundColor;
    property TitleText: string read GetTitleText write SetTitleText;
  end;

implementation

var
  gBackgroundColor: TColor;
  gTitleText: string;

function TMyCompsSettings.GetBackgroundColor(): TColor;
begin
  Result := gBackgroundColor;
end;

procedure TMyCompsSettings.SetBackgroundColor(const v: TColor);
begin
  gBackgroundColor := v;
end;

function TMyCompsSettings.GetTitleText(): string;
begin
  Result := gTitleText;
end;

procedure TMyCompsSettings.SetTitleText(const v: string);
begin
  gTitleText := v;
end;

但是,我忽略了IDE还将维护var状态,因此当我:
1.将TMyCompsSettings组件添加到表单
1.在对象检查器中将MyCompsSettings1.TitleText设置为“ABC”
1.打开其他项目
1.将TMyCompsSettings组件添加到表单

  • 〉MyCompsSettings1.TitleText已经是'ABC'!
    当然,这是显而易见的,但我没有考虑到这一点,这打破了我的整个模型。
    是否有正确的方法来做到这一点?例如,在设计时使用字段,在运行时使用变量,例如:
type
  TMyCompsSettings = class(TComponent)
  private
    FAuthoritative: Boolean;     // Set to true for first instance, which will be MyCompsSettings()
    FBackgroundColor: TColor;
    FTitleText: string;

    function GetBackgroundColor(): TColor;
    procedure SetBackgroundColor(const v: TColor);
    function GetTitleText(): string;
    procedure SetTitleText(const v: string);
  published
    property BackgroundColor: TColor read GetBackgroundColor write SetBackgroundColor;
    property TitleText: string read GetTitleText write SetTitleText;
  end;

implementation

function TMyCompsSettings.GetBackgroundColor(): TColor;
begin
  if FAuthoritative or ( csDesigning in ComponentState ) then
    Result := FBackgroundColor
  else
    Result := MyCompsSettings().BackgroundColor;
end;

procedure TMyCompsSettings.SetBackgroundColor(const v: TColor);
begin
  if FAuthoritative or ( csDesigning in ComponentState ) then
    FBackgroundColor := v
  else
    MyCompsSettings().BackgroundColor := v;
end;

function TMyCompsSettings.GetTitleText(): string;
begin
  if FAuthoritative or ( csDesigning in ComponentState ) then
    Result := FTitleText
  else
    Result := MyCompsSettings().TitleText;
end;

procedure TMyCompsSettings.SetTitleText(const v: string);
begin
  if FAuthoritative or ( csDesigning in ComponentState ) then
    FTitleText := v
  else
    MyCompsSettings().TitleText := v;
end;
smtd7mpg

smtd7mpg1#

由于IDE是一个进程,因此进程中的全局变量将保留在进程中。
如果您希望能够跟踪IDE中不同项目之间的设置(如果它们在一个项目组中,则可能同时打开两个窗体),则需要找到一种跟踪它们的方法。
也许最简单的方法是将设置保存在一个对象中-可以在initialization节中加载一个全局对象,并在finalization节中释放。您的基于表单的TComponent可以检查它们是否处于设计模式,如果它们处于设计模式,则它们创建一个新的单独的对象副本,如果不是,则它们连接到对象的全局示例。
其他访问这些设置的组件都将使用全局对象--为了确保对象的内容与设计时版本相匹配,您需要用任何加载的表单版本覆盖全局对象。您可以在TComponentLoaded例程中完成此操作。
这段代码是未检查的,但应该给予你一个大纲,它可能如何工作。

implementation

  type
  TMySettings = class(TPersistent)     // so you can .Assign
  protected
    FOwner: TPersistent;
    function GetOwner(): TPersistent; override;
  public
    constructor Create(AOwner: TPersistent); reintroduce;
  property 
    Owner: TPersistent read GetOwner();
  end;

  TMySettingsComponent = class(TComponent)
  protected
    procedure Loaded(); override;

  public
    destructor Destroy(); override;
    procedure AfterConstruction(); override;
  end;

implementation
  var
    gpMySettings: TMySettings;

  constructor TMySettings.Create(AOwner: TPersistent);
  begin
    Self.FOwner:=AOwner;
    inherited Create();
  end;

  function TMySettins.GetOwner(): TPersistent;
  begin
    Result:=Self.FOwner;
  end;

  destructor TMySettingsComponent.Destroy;
  begin
    if(Self.FSettings.Owner = Self) then
      FreeAndNIl(Self.FSettings);
    inherited;
  end;

  procedure TMySettingsComponent.AfterConstruction();
  begin
    // our ComponentState will not yet be set
    if( (Self.Owner <> nil) And
        (csDesigning in Self.Owner.ComponentState) ) then 
      Self.FSettings:=TMySettings.Create(Self) 
    else
      Self.FSettings:=gpMySettings;
    inherited;
  end;

  procedure TMySettingsComponent.Loaded;
  begin
    if( (Self.FMySettings.Owner=Self) And
        (gpMySettings<>nil) ) then
      gpMySettings.Assign(Self.FMySettings);
  end;

initialization
  gpMySettings:=TMySettings.Create(nil);

finalization
  FreeAndNIl(gpMySettings);

您还需要确保在TMySettingsComponent中,当用户更改属性时更新全局对象。这可能非常简单:

procedure TMyComponentSettings.SetBackgroundColour(FNewValue: TColor);
  begin
    if(Self.FSettings.FBkColour<>FNewValue) then
    begin
      Self.FSettings.FBkColour:=FNewValue;
      if( (Self.FSettings.Owner=Self) And
          (gpMySettings<>nil) ) then
        gpMySettings.Assign(Self.FSettings);
        // -- or use gpMySettings.FBkColour:=FNewValue;
    end;
  end;

相关问题