VCL for PHP チャートコンポーネント - パート5 - プロパティエディタ

By: Tomohiro Takahashi

Abstract: この記事では、VCL for PHP チャートコンポーネントの作成について解説します。なお、この記事はDelphi for PHPの開発者であるJose Leon氏のブログを再構成したものです。

VCL for PHP チャートコンポーネント - プロパティエディタ

前回の記事では配列型のSeriesプロパティを含むいくつかのプロパティをチャートコンポーネントに追加しました。しかしSeriesプロパティは、オブジェクトインスペクタで直接編集することができません。ユーザーがこのプロパティを編集できるようにするには、ユーザーがビジュアル的に全てのシリーズを作成してその属性を設定を行えるプロパティエディタを記述する必要があります。

この記事では、Delphi for Windowsを使用してビジュアルなプロパティエディタを作成する方法および、それをSeriesプロパティに結び付けて情報を読み書きする方法について解説します。

プロパティの準備

最初の記事で、Open Flash Chartをラップするには何を行わなければならないかを知るために、それを分析し、機能に関する情報を収集しました。

Seriesプロパティは、チャートが表示しようとする全ての情報を保持する責務があるでしょう。

全てのサンプルおよびドキュメントをチェックすると、シリーズが持ち得る属性の一覧が分かります。そして注意しなければならないのは、ほとんどのものは共通しているものの、全ての属性を全てのタイプのシリーズに適用できるわけではないということです。

以下は、私が抽出した一覧です:

  • Alpha
  • Animate
  • Color
  • DataSource
  • DotSize
  • FunFactor
  • HaloSize
  • Hint
  • KeySize
  • KeyText
  • Name
  • StartAngle
  • Type
  • OutlineColor
  • Width
  • XLabelsField
  • XValuesField
  • YLabelsField
  • YValuesField
  • OnClick
  • OnCustomize
  • OnGetData

Open Flash Chartのドキュメントやサンプルを読むと、その全ての属性は名前から判断できますが、そのいくつかはイベントであることに注意してください。そうなのです、イベントなのです。プロパティエディタでイベントハンドラを作成して結び付けることが可能です。読み進めれば、どのように実現するのか分かります。

配列エディタから継承する

Seriesのような配列プロパティ用に、配列エディタと呼ばれるプロパティエディタが予め用意されています。これは、サブプロパティを含むことができる配列プロパティを編集する便利な機能を提供します。IDEからそのプロパティを読み込む全ての過程、つまり正しい値でプロパティエディタの項目を埋め、その情報を書き戻すという作業は、その基本クラスで行われます。ですから、私たちは必要に応じてそれをカスタマイズするだけでよいのです。

プロパティエディタを記述するには、Delphi for Windowsが必要になります。この記事を書いている時点では、Delphi 2007が必要になります。パッケージを新規に作成し、requires部に2つの.dcpファイル(D4PHPTools.dcp と nativePropertyEditors.dcp)を追加しなければなりません。前者は、IDEや基本クラスとのやり取りを行う共通ルーチンを含んでいます。後者は、継承可能なネイティブなプロパティエディタを全て含んでいます。実際にはD4PHPTools.dcpだけでよいのですが、既存のプロパティエディタから継承しようとしているので、後者も必要になります。

プロパティエディタのコードを含むことになるユニットをパッケージの中に作成する必要があります。名前をuSeriesPropertyEditor.pasにしましょう。

プロジェクトマネージャは次のようになるはずです:

Hide image

新しいプロパティエディタを記述するには、単にTArrayPropertyEditorから継承してください:

unit uSeriesPropertyEditor;

interface

uses Windows, Classes, Dialogs, Controls,
    Forms, Graphics, SysUtils, D4PHPIntf,
    ComCtrls, valedit, grids,
    uNativePropertyEditors, uArrayEditor;

type
    TSeriesPropertyEditor = class(TArrayPropertyEditor)
    private
        latestkeyname: string;
    public
        procedure beforeShowEditor(dialog: TForm); override;
        procedure vePropertiesGetPickList(Sender: TObject; const KeyName: string; Values: TStrings);
        procedure vePropertiesEditButtonClick(Sender: TObject);
        procedure vePropertiesDblClick(Sender: TObject);
        procedure vePropertiesSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
        procedure GetNewItemCaption(Sender: TObject; var itemcaption: string);
    end;

implementation
end.

オーバーライドするメソッドは、このエディタが動作する準備として呼び出されるbeforeShowEditorだけです。残りのメソッドは、ヘルパーメソッドや、このエディタのコントロールのためのイベントハンドラです。

メソッドの実装

最初に実装するメソッドはbeforeShowEditorです。dialogパラメーターにはユーザーに表示するフォームが含まれているので、カスタマイズすることができます:

procedure TSeriesPropertyEditor.beforeShowEditor(dialog: TForm);
begin
    inherited;
    latestkeyname := '';
    with dialog as TArrayEditorDlg do begin
        OnGetNewItemCaption := GetNewItemCaption;
        caption := 'Series Editor';
        btnNewSubItem.Visible := false;
        btnLoad.Visible := false;
        captionproperty := 'Name';
        btnDelete.Top := btnNewSubItem.top;
        with defaultproperties do begin
            add('Alpha=');
            add('Animate=false');
            add('Color=');
            add('DataSource=');
            add('DotSize=1');
            add('FunFactor=1');
            add('HaloSize=1');
            add('Hint=');
            add('KeySize=');
            add('KeyText=');
            add('Name=');
            add('StartAngle=0');
            add('Type=ctLine');
            add('OutlineColor=');
            add('Width=1');
            add('XLabelsField=');
            add('XValuesField=');
            add('YLabelsField=');
            add('YValuesField=');
            add('OnClick=');
            add('OnCustomize=');
            add('OnGetData=');
        end;
        veProperties.OnGetPickList := vePropertiesGetPickList;
        veProperties.OnEditButtonClick := vePropertiesEditButtonClick;
        veProperties.OnSelectCell := vePropertiesSelectCell;
        veProperties.OnDblClick := vePropertiesDblClick;
        veProperties.DefaultColWidth:=132;
    end;
end;

最初の数行では、エディタのキャプションや利用可能なボタンを設定しています。また、既存の属性の中のどのプロパティが項目のキャプションを設定するのに利用されるのかを指定しています。今回の場合、Nameを指定していますので、ユーザーがエディタの右側でその値を変更すると、シリーズの名前も変更されます。

その後、シリーズの全てのデフォルトプロパティをデフォルト値とともに追加し、最後にイベントハンドラを結び付けています。

新規シリーズのデフォルトの名前を設定する

procedure TSeriesPropertyEditor.GetNewItemCaption(Sender: TObject;
  var itemcaption: string);
begin
    itemcaption := 'Serie' + inttostr((sender as TArrayEditorDlg).tvItems.Items.Count + 1);
end;

このメソッドは、ユーザーが項目(今回の場合はシリーズ)を新規に作成した時に呼び出されます。シーケンス番号を付けたシリーズの名前をitemcaptionに入れて返します。

プロパティエディタからイベントを作成する

procedure TSeriesPropertyEditor.vePropertiesDblClick(Sender: TObject);
var
    ename: string;
    control: string;
    x, y: integer;
begin
    if (latestkeyname = 'OnClick') then begin
        ename := trim((sender as TValueListEditor).Values[latestkeyname]);
        control := (sender as TValueListEditor).Values['Name'];
        if (ename = '') then ename := control + 'Click';
        addEvent('?>' + #13 + #10 + #13 + #10 + '<?php', ename, x, y);
        (sender as TValueListEditor).Values[latestkeyname] := ename;
        GotoPos(x, y);
    end;

    if (latestkeyname = 'OnGetData') then begin
        ename := trim((sender as TValueListEditor).Values[latestkeyname]);
        control := (sender as TValueListEditor).Values['Name'];
        if (ename = '') then ename := control + 'GetData';
        addEvent('' + #13 + #10 + #13 + #10 + '', ename, x, y);
        (sender as TValueListEditor).Values[latestkeyname] := ename;
        GotoPos(x, y);
    end;
    if (latestkeyname = 'OnCustomize') then begin
        ename := trim((sender as TValueListEditor).Values[latestkeyname]);
        control := (sender as TValueListEditor).Values['Name'];
        if (ename = '') then ename := control + 'Customize';
        addEvent('' + #13 + #10 + #13 + #10 + '', ename, x, y);
        (sender as TValueListEditor).Values[latestkeyname] := ename;
        GotoPos(x, y);
    end;
end;

このメソッドは、セルがダブルクリックされた時に実行されます。そしてセルがイベントであるかチェックしたら:

  • セルの値を取得する
  • シリーズの名前を取得する
  • addEventメソッドを使用して、IDEで編集中のPageにメソッドを追加する
  • 新しいイベントハンドラの値として、その値を設定する
  • エディタでその位置に移動する

以上のことを、シリーズが持つ3つのイベントについて行います。

プロパティに選択肢を提供する

procedure TSeriesPropertyEditor.vePropertiesGetPickList(Sender: TObject;
  const KeyName: string; Values: TStrings);
begin
    if (KeyName = 'OnGetData') or (KeyName = 'OnCustomize') then begin
        GetExistingEvents(values);
    end;
    if (KeyName = 'Type') then begin
        with values do begin
            add('ctLine');
            add('ctLineDot');
            add('ctLineHollow');
            add('ctBar');
            add('ctBarFilled');
            add('ctBarGlass');
            add('ctBar3D');
            add('ctBarSketch');
            add('ctBarHorizontal');
            add('ctBarStacked');
            add('ctArea');
            add('ctAreaHollow');
            add('ctPie');
            add('ctScatter');
            add('ctScatterLine');
            add('ctRadar');
        end;
    end;
    if (KeyName = 'Animate') then begin
        with values do begin
            add('true');
            add('false');
        end;
    end;
    if (KeyName = 'DataSource') then begin
        getcomponents('Datasource', values);
    end;
end;

そして最後に、このメソッドは、ユーザーが値を編集するためにドロップダウンリストを開いたときに呼び出され、適切な値の一覧を提供することができます。今回の場合、Typeにはユーザーが作成可能な全てのチャートタイプを、Animateにはtrueまたはfalseを、DataSourceにはフォーム上のDatasourceコンポーネントの一覧を提供して表示します。getcomponents関数は、IDEが提供する組み込み関数です。

初期化

このプロパティエディタをOpenChartコンポーネントのSeriesプロパティに結び付けるには、次のようにinitialization部を使用してください:

initialization
    //Register all property editors
    registerPropertyEditor('OpenChart', 'Series', TSeriesPropertyEditor);

これによりIDEは、ユーザーがこのプロパティを編集しようとした時にどのプロパティエディタを使用するのか分かります。

結果

このプロパティエディタは次のように動作します:

Hide image

Click to see full-sized image

Server Response from: ETNASC04