処理を共通化するには?

解決


茶色  2007-02-08 19:39:40  No: 24831  IP: 192.*.*.*

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;

の様に、条件文で処理を分岐させる以外でスマートなやり方はないでしょうか?

編集 削除
HOta  2007-02-08 19:46:14  No: 24832  IP: 192.*.*.*

Case文です。

Case Index of
0:
    Form2.Label1.Caption := 'Hello World';
1:
    Form3.Label1.Caption := 'Hello World';
2:
    Form4.Label1.Caption := 'Hello World';
end;

編集 削除
茶色  2007-02-08 20:11:48  No: 24833  IP: 192.*.*.*

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」で操作できる。

編集 削除
みんみん  2007-02-08 21:29:37  No: 24834  IP: 192.*.*.*

数値から処理対象の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;

編集 削除
田中  2007-02-08 23:33:22  No: 24835  IP: 192.*.*.*

複数のオブジェクトを管理するなら、こんな方法もあります

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;

編集 削除
茶色  2007-02-09 10:00:57  No: 24836  IP: 192.*.*.*

みんみんさん
田中さん
回答有難う御座います。

早速試して見たのですが、どちらの場合でも各Formに貼り付けられた
コンポーネントへの処理部分でコンパイルエラーになってしまいます。
(それ以前に貼り付けたコンポーネントがリストに出て来ない)

勉強不足でスミマセンが、上記の方法で、各Formに貼り付けられた
コンポーネントへアクセスする方法は有りますでしょうか?

編集 削除
にしの  2007-02-09 10:28:12  No: 24837  IP: 192.*.*.*

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;

こんな感じで。
# 未検証です

編集 削除
えーと  2007-02-09 10:35:30  No: 24838  IP: 192.*.*.*

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;

詳しくはヘルプで。

編集 削除
えーと  2007-02-09 10:49:31  No: 24839  IP: 192.*.*.*

あ、それから普通の TForm には Label1 というようなフィールドはありませんので、
実際の子フォームの型にキャストしてからアクセスする必要があります。

編集 削除
茶色  2007-02-09 15:26:54  No: 24840  IP: 192.*.*.*

にしのさん
えーとさん
回答有難う御座います。

にしのさん
コンパイルエラーにはならなくなったのですが、実行するとエラーになります。
どうにかならないか、もう少し考えてみたいと思います。


えーとさん
(Screen.ActiveForm as TForm2).Label1.Caption := 'Hello World';
上の様にキャストして、Form2をアクティブにした状態で行うと上手く行くのですが、これだとキャスト時に使用するFormを指定する必要があるので、今回の目的にはちょっと適していない様です。


せっかく教えて頂いたのに、この様な物言いでスミマセン m(_ _ ")m

編集 削除
orz  2007-02-09 16:48:20  No: 24841  IP: 192.*.*.*

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');

いかがかな?

編集 削除
えーと  2007-02-09 17:51:56  No: 24842  IP: 192.*.*.*

多態性を利用した処理の共通化をするには

1)下位クラスに型キャストをする。
2)上位クラスを共通化する。

これしかないですね。1)がいやなら orz さんのように2)にしなければなりません。

編集 削除
茶色  2007-02-09 17:59:14  No: 24843  IP: 192.*.*.*

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だけで考えています。

編集 削除
茶色  2007-02-09 17:59:56  No: 24844  IP: 192.*.*.*

えーとさん有難う御座います。

編集 削除