たびたびお世話になります。
Windows7、Delphi2007です。
子フォームを生成する場合、
Form2 := TForm2.Create(Self);
とすると思います。
この「Form2」「TForm2」の部分を動的に変えたいのです。
イメージとしては
yobidasi( TForm2 );
とか
yobidasi( TForm3 );
yobidasi( TForm4 );
のように引数を指定し呼び出して、
procedure yobidasi( param : ????? );
var
frm : param;
begin
frm := param.Create(Self);
frm.Showmodal;
end;
てな感じで指定のフォームを生成して表示したいのです。
よろしくお願いします。
procedure yobidasi( param : TFormClass );
var
frm : TForm;
begin
frm := param.Create(Self);
frm.Showmodal;
end;
かな。「クラス参照」でヘルプを参照したら説明が載ってます。
バッチリ表示できました。ありがとうございます。
ただ上記イメージにて割愛した部分にて不都合が出てしまいましたので
後出しになって申し訳ないですが引き続きお願いします。
実はForm2を呼び出す際、Form1から、Form2にあるpublic関数(kidou)を実行し、
kidouの中でForm2.Showmodalを行っています。
// 旧
Form2 := TForm2.Create(Self);
Form2.kidou; // Form2のpublic関数 この中でForm2.Showmodal
// 新
procedure yobidasi( param : TFormClass );
var
frm : TForm;
begin
frm := param.Create(Self);
frm.kidou; // ←未定義の識別子に
end;
コンパイルが通らないことが感覚では理解できるのですが
どのようにすればよいでしょうか。
よろしくお願いします。
TForm2(frm).kidou のようにしてやれば実行はできますが
それではfrmが必ずTForm2(またはその派生クラス)でなくてはいけないから、動的生成する意味がないですよね。
実際にやりたいことは、TForm2, TForm3, TForm4, ... がすべて kidou というメソッドを持っていて、それを呼び出したいということだと思いますが
それを実現するには、まず kidou という仮想メソッドを持つ共通の親クラスを作らなくてはいけません。
type
TForm_Parent = class(TForm)
public
procedure kidou; virtual; abstract;
end;
その他のフォームはこのクラスから継承し、kidouメソッドをオーバーライドして実装します。
type
TForm2 = class(TForm_Parent)
public
procedure kidou; override;
end;
これで下のように動的にクラスを生成してメソッドを呼び出せます。
type
TForm_ParentClass = class of TForm_Parent;
procedure yobidasi(param: TForm_ParentClass);
var
frm: TForm_Parent;
begin
frm := param.Create(Self);
frm.kidou;
end;
ちなみに、やりたいことはそうじゃなくて「TForm2の時だけkidouを呼び出す」だというのなら、以下の一文で済みます。
if frm is TForm2 then TForm2(frm).kidou;
ついでに言うと、わざわざ親クラスを用意しなくても
ShowModal自体が仮想メソッドなので、これをオーバーライドしてしまうというのもアリです。
type
TForm2 = class(TForm)
public
function ShowModal: Integer; override;
end;
function TForm2.ShowModal: Integer;
begin
// TForm2.kidou でやっていることをここに書く
// その後で継承元のShowModalを呼び出す
Result := inherited ShowModal;
end;
これなら呼び出す方はauさんのコードのままでOKです。
procedure yobidasi( param : TFormClass );
var
frm : TForm;
begin
frm := param.Create(Self);
frm.Showmodal; // kidouでやっていたことをこの中でやってしまう
end;
ご回答ありがとうございます。とてもわかりやすいです。
> 実際にやりたいことは、TForm2, TForm3, TForm4, ... がすべて kidou というメソッドを持っていて、それを呼び出したいということだと思いますが
そのとおりです。
ですがモノによっては、kidou関数は引数がついてたり返り値があったりなのでやっぱり無理か…
と挫折しかけましたが kidouのオーバーロードなり、別の関数なりを親クラスに定義しておけばできそうですね
そうすると呼び出し側で条件分岐しなければいけないので
動的に呼び出す意味がますます薄れるかと思いますが、ご容赦ください
さて、親クラスを継承する方法で進め、コンパイルはできました。
しかし実行時、Form2のkidou関数内ではForm2がnilになっており、エラーになってしまいます。
前段階のfrm変数は生成できているようなのですが…
// Form1---------------------------------------------------------
TForm_ParentClass = class of TForm_Parent;
TForm1 = class(TForm)
…
procedure TForm1.Button1Click(Sender: TObject);
begin
yobidasi(TForm2);
end;
procedure TForm1.yobidasi(param: TForm_ParentClass);
var
frm: TForm_Parent;
begin
frm := param.Create(Self);
frm.kidou;
end;
// Form2---------------------------------------------------------
TForm2 = class(TForm_Parent)
public
{ Public declarations }
procedure kidou; override;
end;
procedure TForm2.kidou;
begin
inherited;
Form2.ShowModal; // ←ここでForm2がnil※※※※※※※※※※※※
end;
以上、よろしくお願いします。
> しかし実行時、Form2のkidou関数内ではForm2がnilになっており、エラーになってしまいます。
Form2というのはフォームを自動生成するときに使われる変数なので
自分で作った場合はそこには入りません。
そもそもTForm2のメソッドなのですから、自分自身を参照するのにわざわざ外部変数に頼る必要はなくて
ShowModal;
だけでいいです。どうしても前に何か付いていないと不安だというなら
Self.ShowModal;
とします。
> だけでいいです。どうしても前に何か付いていないと不安だというなら
> Self.ShowModal;
> とします。
不安です。笑
Self.ShowModalとしました。
完全に納得です。ありがとうございました。
ツイート | ![]() |