Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi】コンポーネントのプロパティ名や値をロジックで取得・変更

各画面のコンポーネントのプロパティの値は、
オブジェクトインスペクタを使って設定するか、ソース内でロジックで設定するのが一般的です。

しかしコンポーネントやプロパティを実行中のプログラム内で名前で検索して、
値を参照または変更したい局面もあるかと思います。

今回はそれらの手法を紹介します。

 


プロパティの読み取り

前提として、今回使用する各処理では
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;

処理結果イメージ:

Button1の『Hint』プロパティに
『マウスをかざすとヒントが表示されます』
という文字列を設定していた場合

 
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;

 
処理結果イメージ: