16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル
"TNotifyPersistent (長いです)"
みなさんこんにちは
子オブジェクトを保有するオブジェクトを published なプロパ
ティにすると、オブジェクトインスペクタ上で「子」をいじっても
「親」へ伝わりません。
「子」に「親」への参照を持たせてあれば良いのですが、「子」
がたくさん居る場合は美しくないです。
TFont が OnChange を持っていることをヒントに作成しました。
type
TNotifyPersistent = class(TPersistent)
private
FUpdateCount: Integer;
FOnChange: TNotifyEvent;
protected
procedure Changed; virtual;
procedure ChangedProc(Sender: TObject); virtual;
public
procedure BeginUpdate;
procedure EndUpdate;
property OnChange: TNotifyEvent read FOnChange
write FOnChange;
end;
implementation
{ TNotifyPersistent }
procedure TNotifyPersistent.BeginUpdate;
begin
Inc(FUpdateCount);
end;
procedure TNotifyPersistent.EndUpdate;
begin
Dec(FUpdateCount);
Changed;
end;
procedure TNotifyPersistent.Changed;
begin
if (FUpdateCount = 0) and Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TNotifyPersistent.ChangedProc(Sender: TObject);
begin
if Sender <> Self then
Changed;
end;
「使用例」
間もなく公開の TEditor からの抜粋になりますが(^^;)
type
TEditorMark = class(TNotifyPersistent)
private
FColor: TColor; // 表示色
FVisible: Boolean; // 表示するしないフラグ
procedure SetColor(Value: TColor);
procedure SetVisible(Value: Boolean);
public
constructor Create;
procedure Assign(Source: TPersistent); override;
published
property Color: TColor read FColor
write SetColor;
property Visible: Boolean read FVisible
write SetVisible;
end;
TEditorMarks = class(TNotifyPersistent)
private
FEofMark: TEditorMark; // [EOF] マーク
FRetMark: TEditorMark; // 改行マーク
FUnderline: TEditorMark; // アンダーライン
procedure SetEofMark(Value: TEditorMark);
procedure SetRetMark(Value: TEditorMark);
procedure SetUnderline(Value: TEditorMark);
public
constructor Create;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
published
property EofMark: TEditorMark read FEofMark
write SetEofMark;
property RetMark: TEditorMark read FRetMark
write SetRetMark;
property Underline: TEditorMark read FUnderline
write SetUnderline;
end;
implementation
{ TEditorMark }
constructor TEditorMark.Create;
begin
FColor := clGray;
end;
procedure TEditorMark.Assign(Source: TPersistent);
begin
if Source is TEditorMark then
begin
FColor := TEditorMark(Source).FColor;
FVisible := TEditorMark(Source).FVisible;
Changed; // 味噌
end
else
inherited Assign(Source);
end;
procedure TEditorMark.SetColor(Value: TColor);
begin
if FColor <> Value then
begin
FColor := Value;
Changed; // 味噌
end;
end;
procedure TEditorMark.SetVisible(Value: Boolean);
begin
if FVisible <> Value then
begin
FVisible := Value;
Changed; // 味噌
end;
end;
{ TEditorMarks }
constructor TEditorMarks.Create;
begin
FEofMark := TEditorMark.Create;
FEofMark.OnChange := ChangedProc; // 味噌
FRetMark := TEditorMark.Create;
FRetMark.OnChange := ChangedProc; // 味噌
FUnderline := TEditorMark.Create;
FUnderline.OnChange := ChangedProc; // 味噌
end;
destructor TEditorMarks.Destroy;
begin
FEofMark.Free;
FRetMark.Free;
FUnderline.Free;
inherited Destroy;
end;
procedure TEditorMarks.Assign(Source: TPersistent);
begin
if Source is TEditorMarks then
begin
BeginUpdate;
try
FEofMark.Assign(TEditorMarks(Source).FEofMark);
FRetMark.Assign(TEditorMarks(Source).FRetMark);
FUnderline.Assign(TEditorMarks(Source).FUnderline);
finally
EndUpdate;
end;
end
else
inherited Assign(Source);
end;
procedure TEditorMarks.SetEofMark(Value: TEditorMark);
begin
FEofMark.Assign(Value);
end;
procedure TEditorMarks.SetRetMark(Value: TEditorMark);
begin
FRetMark.Assign(Value);
end;
procedure TEditorMarks.SetUnderline(Value: TEditorMark);
begin
FUnderline.Assign(Value);
end;
としておいて
type
TEditor = class(TCustomControl);
private
FMarks: TEditorMarks;
procedure SetMarks(Value: TEditorMarks);
protected
procedure MarksChanged(Sender: TObject); virtual;
published
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Marks: TEditorMarks read FMarks
write SetMarks;
end;
implementation
constructor TEditor.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMarks := TEditorMarks.Create;
FMarks.OnChange := MarksChanged; // 味噌
end;
destructor TEditor.Destroy;
begin
FMarks.Free;
inherited;
end;
procedure TEditor.SetMarks(Value: TEditorMarks);
begin
FMarks.Assign(Value);
end;
procedure TEditor.MarksChanged(Sender: TObject);
begin
Invalidate;
end;
とすることで、「味噌の連鎖」によりどんなにネストしていても
「子」の更新を知ることが出来ます。MarksChanged には、いろん
なオブジェクトの OnChange をアタッチ出来ますので、
begin
if Sender is TEditorMarks then
..........
else
if Sender is TEditorCaret then
.............
else
.............
といった記述も可能になります。長文失礼しました。m(_ _)m
本田勝彦
Original document by 本田勝彦 氏 ID:(VYR01647)
ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。
Copyright 1996-2002 Delphi Users' Forum
|