【A4】Delphiテクニカルセッション

開発効率を飛躍的に高めるコンポーネント自作テクニック（株）シリアルゲームズ
細川 淳

コンポーネントとは？

コンポーネントとは• コンポーネントとは• プログラムに使える部品• １つの機能を表した再利用可能なプログラム– 単体ではなく、他のプログラムやコンポーネントと組み合わせて使う– 例えば、TMemo を TForm に乗せて使うなど• Delphi では特にデザイナでドロップできる物を指す– TComponent が継承元のもの– 例えば、TStringList や TFileStream などはコンポーネントとは呼ばない• Delphi では、次の２つに大別される• ビジュアルコンポーネント– フォームにドロップしたとき、自身が描画されるコンポーネント• 非ビジュアルコンポーネント– フォームにドロップしたとき、アイコンが表示されるコンポーネント

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

3

Delphi のコンポーネント（１）• 非ビジュアルコンポーネント• ドロップするとアイコンが表示される• 例えば TTimer• 見た目はない• 継承元は基本的に TComponent

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

4

Delphi のコンポーネント（２）• ビジュアルコンポーネント• ドロップすると、コンポーネントの実行時と同じ見た目が表示される• 例えば TStringGrid• 見た目がある• 継承元は、いくつかある• TControl– 全てのコントロールの継承元• TGraphicControl– ユーザーの操作が必要ないコントロールの継承元» TLabel など• TWinControl– Windows のコントロールの継承元（ハンドルを持つ）» Windows コントロールである TMemo など• TCustomControl– 一般的なコントロールの継承元» TDrawGrid など
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

5

コントロールとは• コントロール• ユーザーとやり取りできるコンポーネント• ビジュアルコンポーネントであることが必須• TControl - 全てのコントロールの先祖• TControl• TGraphicControl• TWinControl– TCustomControl» 実際に使われるコントロール

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

6

非ビジュアルコンポーネントの作成

非ビジュアル系コンポーネントの作成• 実際に非ビジュアルコンポーネントを作成してみよう• 機能• ファイルを埋め込む• 埋め込むファイルを選択できる• 名前• TFileEmbedder

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

8

TFileEmbedder の実装（１）ー動作の策定• 必要な機能• ファイルの指定• →ファイルダイアログを開いて指定させたい• ファイルの中身を保存する• →指定されたファイルを読み込んで保存しておきたい• 流れ
ファイルプロパティの横のボタン（・・・）を押す
ファイルダイアログでファイルを開く
ファイルを読み込む
ファイルを保存する本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

9

TFileEmbedder の実装（２）ークラス定義
unit uFileEmbedder;interfaceuses
Windows, Classes;
type
TFileEmbedder = class(TComponent)
private// Variables
FFileName: String;
FData: TMemoryStream;
FCompressed: Boolean;// Methods
procedure ReadData(vStream: TStream);procedure WriteData(vStream: TStream);procedure SetFileName(const Value: String);
protected// Methods
procedure DefineProperties(vFiler: TFiler); override;
public// Constructor & Destructor
constructor Create(vOwner: TComponent); override;
destructor Destroy; override;// Methods
procedure SaveToFile(const vFileName: String);
procedure SaveToStream(const vStream: TStream);// Property
property Data: TMemoryStream read FData;published// Properties
property FileName: String read FFileName write SetFileName;property Compressed: Boolean
read FCompressed write FCompressed default True;end;

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

非ビジュアルコンポーネントなのでTComponent から継承するファイルの中身を保持格納するファイルの名前

published(黄枠内) のプロパティがオブジェクトインスペクタに
表示される
10

TFileEmbedder の実装（３）ー方法• published のプロパティは自動的に保存される• 今回の FileName プロパティについては、何もする必要がない※ただし、一般的な型のデータに限る• ファイルの保存を考える• published プロパティではない Data プロパティを保存するには？
→TComponent のメソッド「DefineProperties」を利用する• 「DefineProperties メソッドは，オブジェクトの非 published データをフォームフ
ァイルなどのストリームに格納するためのメソッドを指定します。」（ヘルプより）
定義
procedure DefineProperties(Filer: TFiler); override;

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

11

TFileEmbedder の実装（４）ーDefineProperties• DefineProperties の使い方
• 定義：procedure DefineProperties(Filer: TFiler);• DefineProperties は、自動的に呼ばれる• コンポーネント固有のデータを格納するための「コンポーネントストリーム」にアクセスする方法が、引数の Filer により提供される• TFiler の使い方ー提供されるメソッド• DefineProperty

Integer や String といった一般的な型のデータ• → TWriter.WriteString, TReader.ReadInteger などが使える場合• DefineBinaryProperty

画像などの一般的ではないデータ• → TStream.Read, Write として読み書きする場合

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

12

TFileEmbedder の実装（５）ーDefinePropertiesの実装
procedure TFileEmbedder.DefineProperties(vFiler: TFiler);
begin
inherited; 必ず inherited する
今回は、ファイルの中身がどんなものでも平気なようにDefineBinaryProperty を使用する

vFiler.DefineBinaryProperty('EmbededData', 保存するデータの名前を指定する（疑似プロパティ名）
保存したデータを読み出す時に呼ばれるメソッドを指定する
ReadData,
データを保存時に呼ばれるメソッドを指定する
WriteData,(FFileName <> '')); 実際に保存したいかどうか。ファイルが未指定名場合は保存しない
end;
第２、３引数の型は TStreamProc
type TStreamProc = procedure(Stream: TStream) of object;

DefineProperty の場合、第２，３引数の型が違い、TReaderProc, TWriterProc となる
type TReaderProc = procedure(Reader: TReader) of object;
type TWriterProc = procedure(Writer: TWriter) of object;

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

13

TFileEmbedder の実装（６）ー WriteData
procedure TFileEmbedder.WriteData(vStream: TStream);var
Size: Integer;
Buff: Pointer;
CompressedBuf: Pointer;
CompressedSize: Integer;
procedure Write0;
begin
Size := 0;
vStream.Write(Size, SizeOf(Integer));
end;
begin
FData.Clear;
if (not FileExists(FFileName)) then begin
Write0;Exit;
end;

if (Size = 0) then begin
Write0;Exit;
end;
if (FCompressed) then begin
Buff := FData.Memory;

グレーアウト部分はファイルの圧縮処理。
コンポーネントの説明とはあまり関係がない
ためグレーアウトとした

ZCompress(Buff, Size, CompressedBuf, CompressedSize);try
vStream.Write(CompressedSize, SizeOf(Integer));vStream.Write(PByte(CompressedBuf)^, CompressedSize);
finally
FreeMem(CompressedBuf);
end;
endelse begin
vStream.Write(Size, SizeOf(Integer));vStream.CopyFrom(FData, 0);
end;
end;

FData.LoadFromFile(FFileName);
Size := FData.Size;• vStream に対してデータを保存する

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

14

TFileEmbedder の実装（７）ーReadData
procedure TFileEmbedder.ReadData(vStream: TStream);var
Size: Integer;
Buff: Pointer;
DecompressedBuf: Pointer;
DecompressedSize: Integer;
begin
vStream.Read(Size, SizeOf(Integer));
FData.Clear;

end
else
FData.CopyFrom(vStream, Size);
FData.Position := 0;
end;

グレーアウト部分はファイルの解凍処理。

コンポーネントの説明とはあまり関係がない
if (FCompressed) then begin
ためグレーアウトとした
GetMem(Buff, Size);try
vStream.Read(PByte(Buff)^, Size);
ZDecompress(Buff, Size, DecompressedBuf, DecompressedSize, 0);
try
FData.Size := DecompressedSize;
CopyMemory(FData.Memory, DecompressedBuf, DecompressedSize);
finally
FreeMem(DecompressedBuf);
end;
finally
FreeMem(Buff);end;• vStream からデータを読み込む

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

15

TFileEmbedder の実装（７）ーコンポーネントの登録
unit uFileEmbedder;interfaceuses
Windows, Classes;
type
TFileEmbedder = class(TComponent)：：
end;
procedure Register;
implementation
uses
SysUtils, ZlibEx, uMessageDialog;
procedure Register;
begin
RegisterComponents('Sample', [TFileEmbedder]);end;• コンポーネントのインストール時に interface 部で定義されている「Register」 という名前の関数が自動的に呼ばれる• RegisterComponents でコンポーネントを登録する
RegisterComponents('パレットの名前', [登録するコンポーネント]);
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

16

TFileEmbedder の実装（８）－まとめ• published プロパティは自動的に保存される• それ以外のデータはコンポーネントストリームに格納するプロパティ格納用の主要な３つのメソッド• TComponent.DefineProperties• TFiler.DefineProperties• TFiler.DefineBinaryProperties• コンポーネントの登録には下記の関数を使う• Register• RegisterComponents

コンポーネントインストール時呼ばれる
Register の中で呼びコンポーネントを登録する

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

17

プロパティエディタの作成

プロパティエディタとは？

• オブジェクトインスペクタから呼び出されるプロパティの編集用エ
ディタのこと• 例えば TMemo で言えば Lines を押したときに出てくるエディタ

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

19

TFileEmbedderEditor の実装（１）• 今回は、ボタンが押されるとファイルダイアログを開くようにしたい
オブジェクトインスペクタの
このボタンが押されたらファイルダイアログを開きたい

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

20

TFileEmbedderEditor の実装（２）ーTPropertyEditor
unit uFileEmbedderEditor; コンポーネントとは、別のユニット！
interface

DesignIntf, DesignEditors には、
デザイン時に必要なインターフェース、プロパティエディタクラスなどが宣言されている

uses
DesignIntf, DesignEditors;

type
TFileEmbedderEditor = class(TStringProperty)
publicprocedure Edit; override;function GetAttributes: TPropertyAttributes; override;end;• プロパティエディタは TPropertyEditor の下位クラスから継承する• TIntegerProperty や TMethodProperty など• 今回は文字列（ファイル名）のため TStringProperty から継承する• 下位クラスから継承すると、プロパティの保存を自分で行う必要がない• そのため、今回は Edit メソッドと GetAttributes メソッドを実装するだけで良い• プロパティエディタは、本体のコンポーネントとソースファイルを必ずわけること• わけないと、実行ファイルに不必要なプロパティエディタやユニットが含まれてしまう
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

21

TFileEmbedderEditor の実装（３）ーEdit
procedure TFileEmbedderEditor.Edit;
begin
with TOpenDialog.Create(Application) do
try
FileName := GetStrValue; GetStrValue でファイル名を TOpenDialog に設定する
Filter := 'すべてのファイル (*.*)|*.*';
if (Execute) then
SetStrValue(FileName); SetStrValue でファイル名をプロパティの値とする
finally
Free;
end;
end;

• TPropertyEditor.Edit メソッドは「・・・」ボタンを押されたとき呼ばれる• ここで、必要ならば自作のフォームを開くこともできる• 今回は TOpenDialog を開き、ファイル名を取得・設定している• GetStrValue, SetStrValue• この２つのメソッドは TStringProperty が提供するメソッドでプロパティの値を取得・設定できる

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

22

TFileEmbedderEditor の実装（４）ーGetAttributes
function TFileEmbedderEditor.GetAttributes: TPropertyAttributes;
begin
Result := [paDialog];
end;• TPropertyEditor.GetAttributes はプロパティの属性を返す
代表的な属性• paDialog• paReadOnly「・・・」ボタンを表示し Edit メソッドを呼び出す
値は変更できない• 例えば TMemo.Lines は、上記２つを指定している

変更できない「・・・」ボタン• 他には、paValueList, paSortList, paSubProperties, paMultiSelect,
paAutoUpdate, paRevertable, paFullWidthName,
paVolatileSubProperties, paVCL, paNotNestable がある

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

23

TFileEmbedderEditor の実装（５）ー登録
procedure Register;
implementation
uses
Dialogs, uFileEmbedder;procedure Register;
begin
RegisterPropertyEditor(
TypeInfo(String), このプロパティの型情報を渡す
プロパティエディタと関連づけるクラス
TFileEmbedder,
プロパティの名前'FileName',
プロパティエディタのクラス
TFileEmbedderEditor);end;• コンポーネントと同じように Register 関数が呼ばれる• RegisterPropertyEditor 関数でプロパティエディタを登録する
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

24

TFileEmbedderEditorの 実装（６）ーまとめ• 編集したいプロパティの型にあったプロパティエディタクラスから派生する• プロパティの属性を適切に設定する• フォームを表示したいならば paDialog を指定する• paDialog なら Edit メソッドをオーバーライドしてフォームを表示
する• Register 関数で RegisterPropertyEditor 関数を呼び、プロパティエディタとして設定する

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

25

ビジュアルコンポーネントの作成

ビジュアルコンポーネントの作成• 基本的には非ビジュアルコンポーネントと同じ• 違うところは継承元• ユーザーの操作が• 必要なければ TGraphicControl• 必要であれば TCustomControl– ただし、ユーザー操作が必要なくても独自の Canvas が必要な場合はTCustomControl を使う– TGraphicControl は、Parent のデバイスコンテキストを使用して描画されるためParent の背景に影響してしまう• を使う• 見た目を表示するために TControl.Paint が呼ばれる• この中で Canvas を使ってコンポーネントの外観を描く
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

27

ビジュアルコンポーネントの作成• 実際にビジュアルコンポーネントを作成してみよう• 機能• 線を引く• 名前• TLineDrawer

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

28

TLineDrawer の実装（１）ー動作の策定• 必要な機能• 線を描く• 流れ
Paint が呼ばれたら線を描く

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

29

TLineDrawer の実装（２）unit uLineDrawer;
interfaceuses
Messages, Classes, Controls;
type
TLineDrawerKind = (lkHorz, lkVert);
TLineDrawer = class(TCustomControl)
privateFKind: TLineDrawerKind;
procedure SetKind(const Value: TLineDrawerKind);protected// Methods
procedure Paint; override;// Message Handlers
procedure CMCtl3DChanged(var vMsg: TMessage); message CM_CTL3DCHANGED;
public// Constructor
constructor Create(vOwner: TComponent); override;
published// Properties
property Kind: TLineDrawerKind read FKind write SetKind default lkHorz;// Inherited Properties
property Anchors;property Color;
property Ctl3D;
property ParentColor;
property ParentCtl3D;
property Visible;
property OnClick;property OnDblClick;end;

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

ビジュアルコンポーネントで独自 Canvas を使用するため
TCustomControl から派生する
Paint メソッドをオーバーライド
して自身を描画する
CM_CTL3DCHANGED
コントロールメッセージに応答する（付録Ａ参照）
property に default を付けるとそのプロパティのデフォルト値にできる（値が設定されるわけではない）
継承元の protected プロパティを
published で再宣言するとオブジェクトインスペクタに表示できるようになる
30

TLineDrawer の実装（３）procedure TLineDrawer.Paint;var
Half: Integer;
Dark, Light: TColor;
beginwith Canvas do begin
Brush.Style := bsSolid;
Dark := Darker(Color);
Light := Lighter(Color);

Ctl3D の値で描画する線の形状を変更する
if (Ctl3D) thencase FKind of
lkHorz: begin
水平線を３Dっぽく描く
Half := Height div 2;
Brush.Color := Dark;
FillRect(Rect(0, 0, Width, Half));

lkVert: begin
Half := Width div 2;

垂直線を３Dっぽく描く

Brush.Color := Dark;
FillRect(Rect(0, 0, Half, Height));
Brush.Color := Light;
FillRect(Rect(Half, 0, Width, Height));
end;
endelse begin
3Dじゃなければ、コントロール矩形いっぱいに
Brush.Color := Color;
四角を描く
FillRect(ClientRect);
end;
end;
end;

Brush.Color := Light;
FillRect(Rect(0, Half, Width, Height));end;• Paint メソッドで Canvas プロパティを使って自身を描画する

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

31

コンポーネントの登録アイコンの作成
Bitmap 16x16 で作成する(上部にコンポーネントパレットがあった時代は 24x24 だった）

XN Resource Editor

画像の左下と同じ色が透過色となる

Image Editor• XN Resource Editor や 旧Borland Image Editor などを使い Delphi
Component Resource (dcr) ファイルを作成する• 現在 Image Editor は提供されていないため、コンパニオンＣＤに入っている XN Resource
Editor を使用する• dcr が無い場合はデフォルトのアイコンで表示される本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

33

新規パッケージの作成と登録

コンポーネントパレットに登録される！
パッケージを右クリック「追加」を選択

ファイル→新規作成からパッケージを選ぶ

パッケージを右クリック「インストール」を選択追加するコンポーネントファイルを選択。
コンポーネント自身・コンポーネントエディタ・アイコン（dcr）を選ぶ

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

34

インストール後にエラーがあったら？

• インストールしたパッケージ内のコンポーネントにバグがあり、読み込み違反などを起こした場合、Delphi 自身の実行に支障がでてしまう。
• しかし、パッケージは起動時に読み込まれるため、そのままでは Delphi を正常に使用することができない。

• そう言った場合は、以下のようにする
1. 一旦 Delphi を終了する
2. 当該パッケージを削除する（名前を変更する）
3. Delphi を起動する• 起動時にエラーが表示され「次回は読み込まないようにするか？」と聞かれるが、これに YES と答えると、存在しても読み込まれなくなってしまうため、必ず NO とする。
4. 修正する
5. 再度インストールする本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

35

付録Ａ ～その他の機能～プロパティのデフォルト値
TLineDrawer = class(TCustomControl)：：
publishedproperty Kind: TLineDrawerKind read FKind write SetKind default lkHorz;
：
：
end;

•
•
•

TLineDrawer の Kind プロパティにはデフォルト値が設定されている
published のプロパティにデフォルト値を設定すると、プロパティの値がデフォルト値と同じ場合、
コンポーネントストリームに保存されない。
例えば TLineDrawer.Kind が lkHorz だった場合、値は保存されない•

値がストリームに保存されて居なくても、コンポーネント生成時に値が設定される（はず）からである••

これによって、容量を削減できる
コンポーネントの作成者は、デフォルト値を指定した場合、コンストラクタなどで値を指定する必要がある• TLineDrawer.Kind のデフォルト値は lkHorz (=0) なので、保存していない• これが lkVert だった場合はコンストラクタや Loaded メソッドで指定する必要がある• TComponent.Loaded メソッドは、コンポーネントの全てのプロパティやデータが読み終わったあとに呼ばれるメソッド。
• あるプロパティAが、他のプロパティBに依存しているときに、プロパティAの初期化に使うことができる

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

37

状態や属性を示すプロパティ•

TComponent.ComponentState• コンポーネントの現在の状態を示すフラグ• csDesigning
デザイン時• csDestroying
コンポーネントが破棄中である•

TControl.ControlState• 実行時にコントロールの現在の状態を示すフラグ• csLButtonDown
マウスの左ボタンが押されている• csCreating
現在コントロールを作成中•

TControl.ControlStyle• コントロールの属性を示すフラグ• csCaptureMouse
マウスをキャプチャする
このフラグをセットすると左ボタンダウンで自動的にキャプチャされる• csSetCaption
コントロールの Caption は明示的に指定されない限り
Name プロパティと同じ値になる※各プロパティの値は、代表的な物のみ記した
その他の値は Classes.pas, Controls.pas を参照

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

38

その他のメソッド・関数•

TComponent.Notification メソッド
• コンポーネントが追加・削除されたときに自動的に呼び出されるメソッド• 定義：
procedure TComponent.Notification(Component: TComponent; Operation: TOperation);type TOperation = (opInsert, opRemove);• 例えば、Form 上に載っている TMenu のインスタンスが削除されると、Form が所有しているコンポーネントの Notification を呼び出す。これによって、TMenu のインスタンスを参照しているコンポーネントがあった場合、適切な処理（参照を nil にするなど）を行うことができる。

•

TComponent.Loaded メソッド

• コンポーネントストリームから全てのプロパティやデータを読み終わると呼ばれるメソッド。

•

•

• 定義：
procedure TComponent.Loaded;
あるプロパティAが、他のプロパティBに依存しているときに、プロパティAの初期化に使うことができる

RegisterNoIcon 関数• コンポーネントを登録するが、ツールパレットには登録しない場合に使う• 例えば TMenuItem は TMenu, TPopupMenu で作成できるが、ツールパレット上にアイコンは存在しない• コンポーネント登録をしておかないとコンポーネントストリームからの読み込み時に失敗してしまう。

※メソッドは、派生先コンポーネントで override して使う

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

39

コントロールメッセージ• コントロールメッセージとは何らかの事態が起きたときにコントロールに通知されるメッセージである• デザインだけではなく、実行時も通知される。
• これらに反応することで見た目の変化などに対応できる• 例えば下記のような物がある
•
•
•
•
•

CM_FONTCHANGED
CM_MOUSEENTER
CM_MOUSELEAVE
CM_CTL3DCHANGED
CM_COLORCHANGED

フォントが変更された
マウスがコントロールの中に入ったマウスがコントロールの中から出た３D状態が変更された
色が変更された※Controls.pas に全メッセージが定義されている
本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

40

コンポーネントの名前・可視性• TCustom～
コンポーネントの先頭に Custom と付いているコンポーネントは継承元クラスとしてデザインされている• 例えば TCustomEdit から TEdit や TMemo が派生している• 何故 Custom～ というコンポーネントが必要なのか？
→ プロパティやメソッドの可視性を変更するため
例えば TLineDrawer では Ctr3D などを published にしていたこれらの絶対必要ではないプロパティは TCustomControl では
全て protected レベルに定義されている
protected に定義することで、派生コンポーネントは、必要なプロパティだけ公開できる• 自分でコンポーネントを作るときも、この規則に沿うと良い
コンポーネントは機能の集まりであり、自分だけが使うわけではない
そのため、規則に沿った方が他人にもわかりやすい

•

• 可視性
•
•

published レベルで定義されたプロパティには実行時型情報が生成される.
strict private, strict protected が Delphi 8 で追加された• 同じユニット内からの可視性を制御出来るようになった

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

41

付録Ｂ ～コンポーネントエディタ～

コンポーネントエディタ－TComponentEditor• 上図のようにコンポーネントを右クリックしたとき独自メニューを表示し、何らかの機能を実行するにはどうすればよいのだろうか？
→TComponentEditor を使うと TMenu を右クリックしたときのような動作を実装できる

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

43

コンポーネントエディタの例
TTitleEditor = class(TComponentEditor)
publicprocedure Edit; override;function GetVerb(vIndex: Integer): String; override;function GetVerbCount: Integer; override;
procedure ExecuteVerb(vIndex: Integer); override;end;function TTitleEditor.GetVerb(vIndex: Integer): String;
begin
case vIndex of
コンテキストメニューの0:
一番上（０番目）にResult := 'Title の編集';'Title の編集' と表示する
else
Result := '';
end;
end;

procedure Register;
implementation

function TTitleEditor.GetVerbCount: Integer;
begin
Result := 1;
メニューに表示する数を返す
end;

procedure Register;
begin
RegisterComponentEditor(TTitleBar, TTitleEditor);
end;

•
•
•
•

GetVerb• コンテキストメニューに表示する文字列を返す
GetVerbCount• コンテキストメニューの数を返す
ExecuteVerb• メニューがクリックされると呼ばれる
Edit• PropertyEditor と同じでここでダイアログを表示
したりする

procedure TTitleEditor.ExecuteVerb(vIndex: Integer);
begin
case vIndex of
0:
Edit;
end;
end;
procedure TTitleEditor.Edit;
begin
if (FTitleEditor = nil) then 独自のエディットフォームを表示する
FTitleEditor := TfrmTitleEditor.Create(nil);
FTitleEditor.Designer := Designer;
FTitleEditor.Initialize(Component);
FTitleEditor.Show;end;

TComponentEditor.Designer インターフェースを渡している
IDesigner にはデザイン時に必要な様々なメソッドが定義されている
例えば Modified メソッドを呼べば変更されたことになり「保存」ボタンが Enable になったりする
詳しくは DesignIntf.pas を参照

本文書の一部または全部の転載を禁止します。本文書の著作権は、著作者に帰属します。

44