各画面のコンポーネントのプロパティの値は、
オブジェクトインスペクタを使って設定するか、ソース内でロジックで設定するのが一般的です。
しかしコンポーネントやプロパティを実行中のプログラム内で名前で検索して、
値を参照または変更したい局面もあるかと思います。
今回はそれらの手法を紹介します。
プロパティの読み取り
前提として、今回使用する各処理では
uses節に『System.TypInfo』を追加する必要があります。
GetPropInfoでプロパティの情報を、
GetPropValueでプロパティの値を取得できます。
結果はVariant型のため、構造化型とポインタ以外のあらゆる型に対応します。
以下のようにロジックを記述することで
コンポーネント内にあるプロパティ名を文字で指定し、値を取得できます。
今回は結果をShowMessageで表示するため、VarToStrで文字列に変換しています。
{*******************************************************************************
目的 : プロパティ値表示処理
引数 : Instance - 対象コンポーネント
PropName - 対象プロパティ名
戻値 :
*******************************************************************************}
procedure ShowPropertyInfo(Instance: TObject; const PropName: string);
var
PropInfo: PPropInfo;
TheValue: Variant;
begin
// プロパティ情報を取得
PropInfo := GetPropInfo(Instance, PropName);
if PropInfo <> nil then
begin
TheValue := GetPropValue(Instance, PropName, True);
ShowMessage(VarToStr(TheValue));
end
else
begin
ShowMessage('指定されたプロパティが見つかりません。');
end;
end;
{*******************************************************************************
目的 : プロパティ値表示サンプル ボタン押下時処理
引数 :
戻値 :
*******************************************************************************}
procedure TForm1.Button1Click(Sender: TObject);
begin
// 例:Button1(TButton)のLeft(Integer)とHint(String)を表示させる
ShowPropertyInfo(Button1, 'Left');
ShowPropertyInfo(Button1, 'Hint');
end;
処理結果イメージ:

『マウスをかざすとヒントが表示されます』
という文字列を設定していた場合
GetPropList関数を使うと、対象コンポーネント内で
GetPropInfoに渡せるプロパティ名の一覧を取得できます。
※基本的にはコンポーネント側でpublished宣言されている型となります。
そのためイベントも(割り当てが無くても)全て表示されます。
また、Constraintsなどの構造化型は正しく取得できません。
これを利用して、以下のようにロジックを記述することで
コンポーネント内にある全てのプロパティ値を取得できます。
(ロジックはMemoに表示する例です。)
{*******************************************************************************
目的 : プロパティ値を全て取得してMemoに表示
引数 : Instance - 対象コンポーネント
戻値 :
*******************************************************************************}
procedure TForm1.ListAllProperties(Instance: TObject);
var
PropList: PPropList;
PropCount, I: Integer;
PropInfo: PPropInfo;
PropValue: Variant;
begin
// 結果表示用
Memo1.Lines.Clear;
// プロパティ数を取得
PropCount := GetPropList(Instance.ClassInfo, tkAny, nil);
if PropCount = 0 then Exit;
// メモリ確保
GetMem(PropList, PropCount * SizeOf(Pointer));
try
// 実際のプロパティ情報を取得
GetPropList(Instance.ClassInfo, tkAny, PropList);
// すべてのプロパティを取得して表示
Memo1.Lines.Add(Format('Properties of %s:', [Instance.ClassName]));
for I := 0 to PropCount - 1 do
begin
PropInfo := PropList^[I];
// プロパティ名を取得(Variant型)
try
PropValue := GetPropValue(Instance, PropInfo^.Name, True);
Memo1.Lines.Add(Format(' %s = %s', [PropInfo^.Name, VarToStr(PropValue)]));
except
on E: Exception do
begin
Memo1.Lines.Add(Format(' %s = <Error: %s>', [PropInfo^.Name, E.Message]));
end;
end;
end;
finally
FreeMem(PropList);
end;
end;
{*******************************************************************************
目的 : プロパティ全表示サンプル ボタン押下時処理
引数 :
戻値 :
*******************************************************************************}
procedure TForm1.Button2Click(Sender: TObject);
begin
// 指定したコンポーネントの全PublishedをMemoに表示
ListAllProperties(chkFD);
end;
処理結果イメージ:

プロパティの書き込み
ここからは逆にプロパティを文字で設定する方法を紹介します。
GetPropValueでプロパティの値を取得したのとは逆に、
SetPropValueで値を設定できます。
以下のようにロジックを記述することで
コンポーネント内にあるプロパティ名を文字で指定し、値を更新できます。
存在しないプロパティを変更しようとするとエラーになるため、
GetPropInfoでプロパティが存在することを事前に確認するのがポイントです。
{*******************************************************************************
目的 : プロパティ値変更処理
引数 : Instance - 対象コンポーネント
PropName - 対象プロパティ名
Value - 変更後の設定値
戻値 :
*******************************************************************************}
procedure SetProperty(Instance: TObject; const PropName: string; const Value: Variant);
begin
if GetPropInfo(Instance, PropName) <> nil then
begin
SetPropValue(Instance, PropName, Value);
end
else
begin
ShowMessage('指定されたプロパティが見つかりません。');
end;
end;
{*******************************************************************************
目的 : SetPropValueサンプル ボタン押下時処理
引数 :
戻値 :
*******************************************************************************}
procedure TForm1.Button3Click(Sender: TObject);
begin
// 対象EditのLeftを10増加(右にずらす)例
SetProperty(edtLIBL, 'Left', edtLIBL.Left + 10);
// 対象EditのAnchorsを右下追従にする例
SetProperty(edtLIBL, 'Anchors', '[akRight,akBottom]');
end;
文字列からコンポーネントを返すFindComponentと併用すると、
以下のようにコンポーネント名・プロパティ名・プロパティ値の全てを
文字列で指定して変更させることも可能です。
{*******************************************************************************
目的 : [edtCOMP] の [edtPROP] を [edtNVAL] に変更 処理
引数 :
戻値 :
*******************************************************************************}
procedure TForm1.Button4Click(Sender: TObject);
var
Cmp: TComponent;
begin
Cmp := FindComponent(edtCOMP.Text);
if (Cmp <> nil) then
begin
SetProperty(Cmp, edtPROP.Text, edtNVAL.Text); //※SetPropertyは1つ上の例を参照
end
else
begin
ShowMessage('指定されたコンポーネントが見つかりません。');
end;
end;
処理結果イメージ:

