お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
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