我有一組組件,它們共享一些全域變數來控制公共屬性,例如樣式特征。
這些當前在運行時通過全域類訪問,例如 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 TIEGlobalSettings.GetBackgroundColor(): TColor;
begin
Result := gBackgroundColor;
end;
procedure TIEGlobalSettings.SetBackgroundColor(const v: TColor);
begin
gBackgroundColor := v;
end;
function TIEGlobalSettings.GetTitleText(): string;
begin
Result := gTitleText;
end;
procedure TIEGlobalSettings.SetTitleText(const v: string);
begin
gTitleText := v;
end;
但是,我忽略了 IDE 也會維護 var 狀態,所以當我:
- 將 TMyCompsSettings 組件添加到表單
- 在物件檢查器中將 MyCompsSettings1.TitleText 設定為“ABC”
- 打開不同的專案
- 將 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 TIEGlobalSettings.GetBackgroundColor(): TColor;
begin
if FAuthoritative or ( csDesigning in ComponentState ) then
Result := FBackgroundColor
else
Result := MyCompsSettings().BackgroundColor;
end;
procedure TIEGlobalSettings.SetBackgroundColor(const v: TColor);
begin
if FAuthoritative or ( csDesigning in ComponentState ) then
FBackgroundColor := v
else
MyCompsSettings().BackgroundColor := v;
end;
function TIEGlobalSettings.GetTitleText(): string;
begin
if FAuthoritative or ( csDesigning in ComponentState ) then
Result := FTitleText
else
Result := MyCompsSettings().TitleText;
end;
procedure TIEGlobalSettings.SetTitleText(const v: string);
begin
if FAuthoritative or ( csDesigning in ComponentState ) then
FTitleText := v
else
MyCompsSettings().TitleText := v;
end;
uj5u.com熱心網友回復:
由于 IDE 是一個行程,行程中的全域變數將保留在行程中。
如果您希望能夠在 IDE 中跟蹤不同專案之間的設定(如果它們在一個專案組中,則可以同時打開兩個表單),那么您將需要找到一種跟蹤它們的方法。
可能最簡單的方法是將設定保存在一個物件中 - 可以在一個部分中加載一個全域物件initialization并在一個部分中釋放finalization。基于表單的 TComponents 可以檢查它們是否處于設計模式,如果它們處于設計模式,那么它們會創建物件的一個??新的單獨副本,如果不是,它們會連接到物件的全域實體。
然后訪問這些設定的其他組件都將使用全域物件 - 以確保物件的內容與設計時版本匹配,您需要使用任何表單加載版本覆寫全域物件。您可以在TComponent的Loaded例程中執行此操作。
此代碼未選中,但應為您提供其作業原理的概要。
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;
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/446165.html
上一篇:Delphi動態陣列變數復用
