{ これは Delphi Advent Calendar 2013 の 12/10 分の記事です }
Delphi といえばコンポーネントを作って開発効率を向上させる事ができるのも特徴の一つですね。コンポーネントの作り方はさておき、慣れないコンポーネントで作業効率を向上させるには
の存在が不可欠だと思います。これらはマニュアルを読まないと理解できないプロパティの値であるとか、オブジェクトインスペクタからは設定できない (しづらい) プロパティの値をセットするのに使われます。
コンポーネントエディタとプロパティエディタの違いですが、前者はコンポーネント全体、あるいは他のプロパティの値に連動して変化するようなプロパティを設定するのに使われます。後者は特定のプロパティのみを更新するものです。オブジェクトインスペクタで設定するものが、今回ご紹介するプロパティエディタです。
プロパティエディタは以下のTPropertyEditor 派生クラスを継承して作ります。
- TBoolProperty
- TCharProperty
- TClassProperty
- TComponentNameProperty
- TComponentProperty
- TDateProperty
- TDateTimeProperty
- TEnumProperty
- TFloatProperty
- TInt64Property
- TIntegerProperty
- TInterfaceProperty
- TMethodProperty
- TNestedProperty
- TSetElementProperty
- TSetProperty
- TStringProperty
- TTimeProperty
- TVariantProperty
- TWideCharProperty
- TWideStringProperty
プロパティの型に応じて派生元のクラスを選択します。
[プロパティエディタ クラスを派生させる (DocWiki)]
http://docwiki.embarcadero.com/RADStudio/ja/%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF_%E3%82%AF%E3%83%A9%E3%82%B9%E3%82%92%E6%B4%BE%E7%94%9F%E3%81%95%E3%81%9B%E3%82%8B
これだけではまだピンとこないと思うので、プロパティエディタを実際に作りながら解説したいと思います。
TLabel (VCL) には Caption というプロパティがあります。TCaption は String 型なので、オブジェクトインスペクタで設定する事ができます。ここにプロパティエディタの存在意義はないように思えますよね?しかしながら、TLabel の Caption は実際には改行コードを含めて複数行表示が可能なのです…オブジェクトインスペクタではどうやっても改行を入力できません。これを可能にするにはプロパティエディタが必要になります。
[frmuStringPropEditor.pas]
{*******************************************************} { } { 文字列用プロパティエディタダイアログ } { } {*******************************************************} unit frmuStringPropEditor;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Controls, Forms, Consts, Dialogs, StdCtrls, ExtCtrls, DesignIntf, DesignEditors;
type {TfrmStringPropertyEditor} TfrmStringPropEditor = class(TForm) pnlBottom: TPanel; mmString: TMemo; btnOK: TButton; btnCancel: TButton; procedure FormCreate(Sender: TObject); procedure mmStringKeyPress(Sender: TObject; var Key: Char); public function ShowModal(PropName: string): Integer; reintroduce; overload; end;
{ TCustomizedStringProperty } TCustomizedStringProperty = class (TStringProperty) public procedure Edit; override; function GetAttributes: TPropertyAttributes; override; end;
implementation
{$R *.dfm}
{TfrmStringPropertyEditor}
procedure TfrmStringPropEditor.FormCreate(Sender: TObject); // フォーム作成時 begin btnOK.Caption := SOKButton; btnCancel.Caption := SCancelButton; mmString.Font.Size := mmString.Font.Size + 1; // 好みで調整してください end;
procedure TfrmStringPropEditor.mmStringKeyPress(Sender: TObject; var Key: Char); // TMemo で 〔Ctrl〕+〔A〕による全選択を可能にする begin if Key = ^A then begin (Sender as TMemo).SelectAll; Key := #$00; end; end;
function TfrmStringPropEditor.ShowModal(PropName: string): Integer; // ShowModal オーバーロードメソッド begin Caption := Format('%s: %s', [SPropertiesVerb, PropName]); result := inherited ShowModal; end;
{ TCustomizedStringProperty }
procedure TCustomizedStringProperty.Edit; // プロパティ編集用メソッド var StringPropertyEditor: TfrmStringPropEditor; begin inherited; StringPropertyEditor := TfrmStringPropEditor.Create(nil); try StringPropertyEditor.mmString.Text := Self.GetStrValue; if StringPropertyEditor.ShowModal(Self.GetName) = mrOK then SetStrValue(StringPropertyEditor.mmString.Text); finally StringPropertyEditor.Free; end; end;
function TCustomizedStringProperty.GetAttributes: TPropertyAttributes; // プロパティエディタ属性取得メソッド begin result := [paDialog, paMultiSelect]; // ダイアログ形式プロパティエディタ, 複数選択対応 end;
end.
ダイアログを出してプロパティを設定するタイプのプロパティエディタはこのようなコードになります。今回のような簡単なプロパティエディタは Edit() メソッドと GetAttributes() メソッドを実装するだけなのでそう難しいものではないと思います。
プロパティエディタはコンポーネント同様、(設計時) パッケージに登録して利用するのですが、そのためにはパッケージ登録用のユニットが必要となります。プロパティエディタのユニットの中にパッケージ登録用のコードを書いてもいいのですが、複数のプロパティエディタを登録できるよう、パッケージ登録用のユニットは別にしておいた方が管理はしやすいかと思います。
[uStringPropEditorReg.pas]
{*******************************************************} { } { String プロパティエディタ登録用ユニット } { } {*******************************************************} unit uStringPropEditorReg;
interface
uses Controls, DesignIntf;
procedure Register;
implementation
uses frmuStringPropEditor; // 文字列用プロパティエディタ
procedure Register; begin // String 型のプロパティ (すべて) に関連付け RegisterPropertyEditor(TypeInfo(string), nil, '', TCustomizedStringProperty);
// TCaption 型のプロパティ (すべて) に関連付け RegisterPropertyEditor(TypeInfo(TCaption), nil, '', TCustomizedStringProperty); end; end.
プロパティが String 或いは TCaption 型の場合にプロパティエディタを表示できるようにしています。TLabel の Caption プロパティ専用にするのは勿体無いですからね。ちなみに、クラスやプロパティ名を限定してプロパティエディタを表示させる事も可能です。
ここまでできれば、パッケージを作って組み込むだけとなります。実際に動作しているスクリーンショットがコレです。

オブジェクトインスペクタで Caption プロパティの右端にある […] ボタンを押すとダイアログ形式のプロパティエディタが開きます。ダイアログのキャプションやボタンのキャプションは文字列定数 (Consts.pas) から持ってきていますので、Delphi 2010 以降ならライブラリの言語を切り替えて英語版を作る事ができます。
この String 用プロパティエディタは VCL / FMX いずれでも利用できるのですが、改行コードを含む TLabel を OS X で表示すると空行ができてしまいます。これは Windows の改行コードが CRLF なのに対し、OS X が LF のみであるからです。この問題を回避するには
- Delphi のプリプロセッサでフォームファイル (*.FMX) をパースしCRLF を LF に置換
- Delphi のポストプロセッサでフォームファイル (*.FMX) をパースしLF を CRLF に置換
このような解決方法が考えられます。他の解決方法として、ターゲットプラットフォームが Windows 以外の場合には OnCreate 等で CRLF を LF に置換するという方法もありますが、いずれにせよ面倒なのでマルチプラットフォームを対象とするのであればコードで改行した方が簡単かもしれません。
プロパティエディタ側に改行コードを指定できるようにするという解決方法では、別プラットフォームをコンパイルする度にプロパティエディタを開かなくてはならず、効率面から考えると本末転倒な気がします。
|