MDIForm内に複数のFormがあって(Form2/Form3/Form4・・・)、これを一つの処理で操作したい場合、
// Form2が選択された
if Index = 0 then begin
Form2.Label1.Caption := 'Hello World';
// Form3が選択された
end else if Index = 1 then begin
Form3.Label1.Caption := 'Hello World';
// Form4が選択された
end else if Index = 2 then begin
Form4.Label1.Caption := 'Hello World';
end;
の様に、条件文で処理を分岐させる以外でスマートなやり方はないでしょうか?
Case文です。
Case Index of
0:
Form2.Label1.Caption := 'Hello World';
1:
Form3.Label1.Caption := 'Hello World';
2:
Form4.Label1.Caption := 'Hello World';
end;
HOtaさん
回答有難う御座います。
こちらの説明不足だったかもしれませんが、If文やCase文を使わずに出来ないか? と言うのを目的としてますので、せっかく教えて頂いたのですが、これだと・・・。
理想としてはこんな感じにならないかなぁと考えております。
// Form2が選択された
if Index = 0 then begin
Form := Form2;
// Form3が選択された
end else if Index = 1 then begin
Form := Form3;
// Form4が選択された
end else if Index = 2 then begin
Form := Form4;
end;
Form.Label1.Caption := 'Hello World';
以降この処理を抜けるまで「Form」で操作できる。
数値から処理対象のTFormを取得したいわけですね。
FindComponent試してみてください。
TFormのnameがForm1,Form2,Form3..となっていることが前提ですが...。
var
frm :TForm;
begin
//質問では index=0 で Form2の処理のようなので
frm :=TForm(FindComponent('Form'+InttoStr(index+2)));
with frm do begin
Label1.Caption :='Hello World';
//以下目的の処理を記述
end; //with
end;
複数のオブジェクトを管理するなら、こんな方法もあります
procedure TForm1.Button1Click(Sender: TObject);
var
obj : TObjectList;
Index: Integer;
begin
Index := 0;
obj := TObjectList.Create(True);
obj.Add(TForm2.Create(Application));
obj.Add(TForm3.Create(Application));
obj.Add(TForm4.Create(Application));
(obj.Items[Index] as TForm).Caption := 'Hello World';
end;
みんみんさん
田中さん
回答有難う御座います。
早速試して見たのですが、どちらの場合でも各Formに貼り付けられた
コンポーネントへの処理部分でコンパイルエラーになってしまいます。
(それ以前に貼り付けたコンポーネントがリストに出て来ない)
勉強不足でスミマセンが、上記の方法で、各Formに貼り付けられた
コンポーネントへアクセスする方法は有りますでしょうか?
Formに貼り付けられたコンポーネントも、FindComponentで探せばよいかと。
みんみんさんのコードで言うならば、
var
frm :TForm;
begin
//質問では index=0 で Form2の処理のようなので
frm :=TForm(FindComponent('Form'+InttoStr(index+2)));
with frm do begin
TLabel(FindComponent('Label1')).Caption :='Hello World';
end; //with
end;
こんな感じで。
# 未検証です
MDI子フォームでも現在アクティブなフォームは Screen.ActiveForm でわかりますよ。
こんな感じ。
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
public
procedure ActiveFormChange(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ActiveFormChange(Sender: TObject);
var
ActiveForm: TForm;
begin
ActiveForm := Screen.ActiveForm;
Caption := ActiveForm.Caption
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Screen.OnActiveFormChange := ActiveFormChange;
end;
詳しくはヘルプで。
あ、それから普通の TForm には Label1 というようなフィールドはありませんので、
実際の子フォームの型にキャストしてからアクセスする必要があります。
にしのさん
えーとさん
回答有難う御座います。
にしのさん
コンパイルエラーにはならなくなったのですが、実行するとエラーになります。
どうにかならないか、もう少し考えてみたいと思います。
えーとさん
(Screen.ActiveForm as TForm2).Label1.Caption := 'Hello World';
上の様にキャストして、Form2をアクティブにした状態で行うと上手く行くのですが、これだとキャスト時に使用するFormを指定する必要があるので、今回の目的にはちょっと適していない様です。
せっかく教えて頂いたのに、この様な物言いでスミマセン m(_ _ ")m
THogeForm=Class(TForm)
public
Procedure SetLabel(aCaption: String); virtual; abstract;
end;
各フォームの継承元を TForm から THogeForm に変更
ソースコード上で、直接書き換え
TForm2=Class(THogeForm)
public
Procedure SetLabel(aCaption: String); override;
end;
Procedure TForm2.SetLabel(aCaption: String);
begin
//Form2では、TLabelに表示
Label1.Caption := aCaption;
end;
TForm3=Class(THogeForm)
public
Procedure SetLabel(aCaption: String); override;
end;
Procedure TForm3.SetLabel(aCaption: String);
begin
//Form3では、TEditに表示
Edit1.Text := aCaption;
end;
これでMDIChildがTHogeFormを継承したものであれば、いかの一行で済みます。
(Screen.ActiveForm as THogeForm).SetLabel('Hello World');
いかがかな?
多態性を利用した処理の共通化をするには
1)下位クラスに型キャストをする。
2)上位クラスを共通化する。
これしかないですね。1)がいやなら orz さんのように2)にしなければなりません。
orzさん
回答有難う御座います。
凄く参考になりました。
”新たなTFormクラスを作って、それを継承して各Formを作る。”
これを利用して、orzさんとはちょっと違ったアプローチでやってみようと思います。
↓他にもこう言う方法でやろうと考えていました。
procedure TForm1.LabelCaption(Index: Integer);
var
lblCommon: TLabel;
begin
if Index = 0 then begin
lblCommon := Form2.Label1;
end else begin Index = 1 then begin
lblCommon := Form3.Label1;
end;
lblCommon.Caption := 'Hello World';
// 以下、lblCommonで処理
end;
※↑単純にする為、Labelだけで考えています。
えーとさん有難う御座います。
ツイート | ![]() |