喫茶XRAYトップページ

[スレッド全体
]

[11062] procedure手続きを手続き名で検索できますか返信 削除
2017/4/10 (月) 19:06:04 taki
動的にコンポーネントを生成しているのですが、text等に記録した文字列から生成したいのです。
TopとかLeftとかCaptionとかは文字列から値を代入できます。
MyButton.ParentはGetComponentByName()という関数を作って文字列'Panel1'からTWinControlを
得ることができたのですが、MyEvent手続きを手続き名'MyEvent'から探す方法が分かりません。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
    MyButton:TButton;
    procedure MyEvent(Sender: TObject);
    function GetComponentByName(AName:String):TComponent;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.GetComponentByName(AName:String):TComponent;
var
  i:integer;
begin
  result := self;     // 無かったらForm1に生成
  if Form1.ComponentCount = 0 then exit;
  for i := 0 to Form1.ComponentCount - 1 do begin
    if Form1.Components[i].Name = AName then begin
      result := Form1.Components[i];
      exit;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyButton := TButton.Create(Self);
  MyButton.Parent := GetComponentByName('Panel1') as TWinControl;
//Panel1上にボタンを生成している
  MyButton.Top := 20;
  MyButton.Left := 20;
  MyButton.Caption := '私のボタン';
  MyButton.OnClick := MyEvent;  // ← ここの値を'MyEvent'から得たい
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if MyButton <> nil then FreeAndNil(MyButton);
end;

procedure TForm1.MyEvent(Sender: TObject);
begin
  beep;
end;

end.


[11064] Re:procedure手続きを手続き名で検索できますか返信 削除
2017/4/10 (月) 20:40:27 Mr.XRAY
▼ takiさん

私もよくは分からんのですが
RTTI (実行時型情報) を利用するとか...

[456_RTTI ( 実行時型情報 ) を使用したメソッドの実行]
http://mrxray.on.coocan.jp/Delphi/plSamples/456_RTTI_InvokeMethod.htm

[458_RTTI ( 実行時型情報 ) を使用したプロパティの列挙]
http://mrxray.on.coocan.jp/Delphi/plSamples/458_RTTI_Properties.htm


[11065] Re2:procedure手続きを手続き名で検索できますか返信 削除
2017/4/10 (月) 23:08:32 taki
▼ Mr.XRAYさん

> 私もよくは分からんのですが
> RTTI (実行時型情報) を利用するとか...


マスター ありがとうございます。

ttp://d.hatena.ne.jp/tales/20121205/1354636256 で
こんなコードを見つけました。

procedure TForm1.Button1Click(Sender: TObject);
var
  method: TMethod;  // 追加
begin
  MyButton := TButton.Create(Self);
  MyButton.Parent := GetComponentByName('Panel1') as TWinControl;
  MyButton.Top := 20;
  MyButton.Left := 20;
  MyButton.Caption := '私のボタン';
// ---------- ここから
  method.Code := @TForm1.MyEvent;
  method.Data := nil;
  MyButton.OnClick := TNotifyEvent(method);
// ---------- ここまで
end;

それで、label1を追加して内容を表示してみました。

procedure TForm1.Button1Click(Sender: TObject);
var
  method: TMethod;
begin
  MyButton := TButton.Create(Self);
  MyButton.Parent := GetComponentByName('Panel1') as TWinControl;
  MyButton.Top := 20;
  MyButton.Left := 20;
  MyButton.Caption := '私のボタン';
// ---------- ここから
  label1.Caption := inttostr(Integer(@TForm1.MyEvent));   // 5977080
  method.Code := Pointer(strtoint(label1.Caption));
  method.Data := nil;
  MyButton.OnClick := TNotifyEvent(method);
// ---------- ここまで
end;

コンパイルする度にlabel1の値は変わりますが、プログラムを単独で動かしても
値が変わることはありません。
なので、この値を保存しておけばいいのかもしれません。
なお、method.Dataについてはもう少し調べる必要があります。



[11066] Re3:procedure手続きを手続き名で検索できますか返信 削除
2017/4/10 (月) 23:24:01 Mr.XRAY
▼ takiさん

> var
>   method: TMethod;  // 追加


あっ,そうか.
実行字型情報では無理そうですね.クラス情報とっていますから.


[11071] Re4:procedure手続きを手続き名で検索できますか返信 削除
2017/4/11 (火) 10:27:51 taki
▼ Mr.XRAYさん
> ▼ takiさん
>
> > var
> >   method: TMethod;  // 追加
>
> あっ,そうか.
> 実行字型情報では無理そうですね.クラス情報とっていますから.


ttp://d.hatena.ne.jp/tales/20121205/1354636256 の内容を
朝、読み返すと私ごときが踏み込んではいけない領域だったみたい。

という事で撤収します。 逃げ恥〜!
お騒がせしました。m(_ _)m


[11072] Re5:procedure手続きを手続き名で検索できますか返信 削除
2017/4/11 (火) 11:05:01 igy
試してないですけど、

Delphiのメソッドをメソッド名から実行する方法
http://www.gesource.jp/weblog/?p=642

とか、いかがですか?


[11074] Re6:procedure手続きを手続き名で検索できますか返信 削除
2017/4/11 (火) 12:59:43 taki
▼ igyさん
> 試してないですけど、
>
> Delphiのメソッドをメソッド名から実行する方法
> http://www.gesource.jp/weblog/?p=642
>
> とか、いかがですか?


ありがとうございます。

実はこのページの内容も参考にして色々と試してみました。(過去形)

procedure ExecMethod(OnObject: TObject; MethodName: string);
をコピペしました。

procedure TForm1.Button4Click(Sender: TObject);
begin
  ExecMethod(Form1,'MyEvent');      // Beep鳴らない
end;

それで新たにButton5を配置して、IDEからイベントを関連付けました。

procedure TForm1.Button5Click(Sender: TObject);
begin
  showmessage('Button5Click');
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
//  ExecMethod(Form1,'MyEvent');      // Beep鳴らない
  ExecMethod(Form1,'Button5Click');   // Showmessage表示された
end;

procedure TForm1.MyEvent(Sender: TObject);
begin
  beep;
end;

IDEで関連付けたButton5Clickとかだったら動くようですが、
動的に生成したイベントの手続き、もしくは標準的なイベントでない?場合は
Form1.MethodAddress()がnilしか返してくれません。

それで、method.Code := @TForm1.MyEvent; にたどり着いたのですが…。

逃げるは恥だが仕方がない!


[11076] Re7:procedure手続きを手続き名で検索できますか返信 削除
2017/4/11 (火) 13:24:15 igy
▼ takiさん
> 動的に生成したイベントの手続き、もしくは標準的なイベントでない?場合は
> Form1.MethodAddress()がnilしか返してくれません。



ヘルプみたら、
> MethodAddress メソッドは,パブリッシュメソッドのアドレスを返します。
って書いてましたね。失礼しました。

なので、


  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure MyEvent(Sender: TObject);   // <===== ここに移動
  private
    { Private 宣言 }
    MyButton:TButton;
    function GetComponentByName(AName:String):TComponent;
  public
    { Public 宣言 }
  end;


だったら、 Beepが鳴るかもしれません。


[11079] Re8:procedure手続きを手続き名で検索できますか返信 削除
2017/4/11 (火) 14:47:21 Mr.XRAY
▼ igyさん

>   TForm1 = class(TForm)
>     Button1: TButton;
>     Panel1: TPanel;
>     Button2: TButton;
>     procedure Button1Click(Sender: TObject);
>     procedure Button2Click(Sender: TObject);
>     procedure MyEvent(Sender: TObject);   // <===== ここに移動
>   private


なるほど,これなら RTTI のテーブルにのりますね.
確認しました.
RTTI にのれば何でもやり放題 !!


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82