Delphi で構造型配列プロパティをつくるメモ
コンポーネントを自作するとき、色々なデータを、コンポーネントとメインフォームの間でやり取りします。
種類 | 宣言する場所 | メモ |
---|---|---|
単純変数 | publish宣言 | オブジェクトインスペクタで編集可能 |
配列変数 | public宣言 | オブジェクトインスペクタは使えません |
構造体を配列にして、プロパティにしたいと思ったら、案外、メンドクサイ。
というわけで、レコード構造型を配列にして使うメモです。
あ、グローバル変数にしちゃえば、簡単なんですが…… 範囲外チェックや、関連する処理はまとめて、コンポーネント側で片付けたいですよね?
コンポーネント側
構造型を宣言します。
最初にデータを仕舞う構造型を宣言します。
private宣言には、Fデータフィールドを置きます。データフィールドは隠蔽が基本です。
プロパティにデータを代入した時に、処理を担当する書き込みメソッドも、ここです。
public宣言には、プロパティの宣言を置きます。配列プロパティは、オブジェクトインスペクタに置けないため、publishにはしません。
読み出しは、データフィールド直接ですが、書き込みはSet○○のメソッドを経由させます。
type
TSampleDat = record
private
FPos:longint; //F○○ : 型; データフィールドを宣言
FMes:String;
procedure SetPos(pos:longint); //procedure Set○○ (○○ :型); 書き込みメソッド宣言
procedure SetMes(Mes:string);
public
property Pos : longint read FPos write SetPos; //property ○○ : 型 read F○○ write Set○○;
property Mes : String read FMes write SetMes; //プロパティ宣言
end; //読みはFデータフィールド直接
//書きは、Set○○で、メソッド手続き必要
コンポーネントの宣言
構造型で、配列変数を宣言します。ここでは固定長にして、データ領域を確保しています。
動的配列にした場合は、別途、Setlength(変数名,長さ); で領域を確保してください。
type
TCustomControl1 = class(TCustomControl) //コンポーネントを宣言
private
{ Private 宣言 }
protected
{ Protected 宣言 }
public
{ Public 宣言 }
Sam:array[0..1024] of TSampleDat; //構造体の配列としてデータフィールドをつくります。
published //この配列変数名が、プロパティ名になります。
{ Published 宣言 }
end;
実現部
書き込みメソッドをつくります。
例なので、単純にデータフィールドに代入していますが、範囲外の外れ値を補正したり、データが変化するときに関連する処理があれば、ここで済ませます。
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TCustomControl1]);
end;
procedure TSampleDat.SetPos(pos: LongInt); //書き込みメソッドの実現部です
begin
FPos:=pos;
end;
procedure TSampleDat.SetMes(Mes: string); //書き込みメソッドの実現部です
begin
FMes:=mes;
end;
end.
メインフォーム側
uses節にコンポーネントのファイル名を
Uses 節の末尾に、上記のカスタムコンポーネントのファイル名を足します。
Pathが気になる時は、このメインフォームと同じディレクトリに置いてください。
あと、ファイル名からは、.pas は省略します。
宣言部について
FormCreate, FormDestroy イベントをオブジェクトインスペクタの該当箇所をクリックして増やします。
publicに、メインフォーム側で使用する名で、カスタムコンポーネントを宣言を書き込みます。
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,SamDatCpt; //コンポーネントを足します
type
TForm2 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
SamAs:TCustomControl1; //使用する名 : Tカスタムコントロール; で宣言
end;
Create と Destroy のイベントを書き込みます。
procedure TForm2.FormCreate(Sender: TObject);
begin
SamAs:=TCustomControl1.Create(Self); //宣言した名 := Tカスタムコンポーネント.Create(Self);
end; //コンポーネントを作成。
procedure TForm2.FormDestroy(Sender: TObject);
begin
SamAs.Free; //宣言した名.Free; コンポーネントを廃棄。
end;
で、準備が整いましたので、配列コンポーネントを使います。
procedure TForm2.Button1Click(Sender: TObject);
var
i:longint;
begin
memo1.text:='';
//書き込み
with SamAs do
begin
Sam[0].pos:=254;
Sam[0].mes:='ささにしき';
Sam[1].pos:=651;
Sam[1].mes:='こしひかり';
Sam[2].pos:=805;
Sam[2].mes:='あきたこまち';
//読み出し
for i:=0 to 2 do
memo1.lines.add(IntToStr(Sam[i].pos)+' '+Sam[i].Mes);
end;
end;
あとがき
ごく単純に、構造型配列をプロパティにして、
コンポーネントの名.構造型の変数名[index].プロパティ := 代入したいデータ; をやろうとすると、
E2064 代入できない左辺値です (Delphi) って、いわれるのです。
で、拡張された構造型を使えば、何とかなりそう? って、Dokiwiki読んだり、ネットを探し回ったりしてました。
いまいち、ピッタリな情報がなかったので、何とかなったから、忘れる前にメモメモ!