MDI子フォームへのアクセス方法

解決


Yama  2006-11-15 06:03:22  No: 23918

初歩的なことで悩んでいます。
MDI親フォームから複数の子フォームを作って、その子フォームには
Imageが載っています。  タイマーでこのイメージへ描画したいのですが、
例えば、Boxという名前のImageへ
Mainform.MDIChildren[0].Box.Canvas.moveto(0,0);
Mainform.MDIChildren[0].Box.Canvas.lineto(100,100);
ではエラーになります。  このアクセス方法をどなたか教えてください。


うんと  2006-11-15 06:46:47  No: 23919

タイマは、親フォームの載ってるんですか?

property MDIChildren[I: Integer]: TForm;

ですから、MDIChildren[0] には、Box という名前のプロパティーもフィールドも
ありません。具体的な子フォームのクラスにキャストすべきですね。


Yama  2006-11-15 15:15:55  No: 23920

>タイマは、親フォームの載ってるんですか?
そうです。子フォームに乗せてもいいのですが、今回は他の理由でも
親フォームから子フォームへのアクセス方法を知りたいと思います。

>具体的な子フォームのクラスにキャストすべきですね。
子フォームは下記のように同じフォーム名で作成されます。

procedure TMainForm.sbClick(Sender: TObject);
var ChildForm: TChildForm;
begin
  ChildForm := TChildForm.Create(Self);
  childForm.show;
end;

この場合、例えば子フォームにメモコンポーネントなどがある場合、
親フォームから特定の子フォームのコンポーネントへアクセスする
方法があれば、教えていただけると助かります。

また、子フォームで、そのメモコンポーネントへアクセスする場合、
memo1.loaodfromfile... ではアクセス可能ですが、
Childform.memo1.loadfromfile..  などフォーム名を入れると不可です。
Childform上でのフォーム名はこの場合、どうなるのでしょうか。


うんと  2006-11-15 19:37:49  No: 23921

>この場合、例えば子フォームにメモコンポーネントなどがある場合、
>親フォームから特定の子フォームのコンポーネントへアクセスする
>方法があれば、教えていただけると助かります。

MDI親フォームから子フォームへのアクセスは、最初のコードのとおり

MDIChildren[I: Integer]

を通してアクセスします。しかし、これは上に示しましたように TForm クラスで
すから、Memo1 や Box などというものはありませんね。具体的にアクセスするに
は、ですからキャストが必要です。

  TChildFrom(MDIChildren[0]).Memo1.LoadFromFile('...');

という感じです。

> また、子フォームで、そのメモコンポーネントへアクセスする場合、

子フォーム内の Button1Click などのメソッドでは、自分自身を参照する self が
隠されています。ですから、どのインスタンスからも、自分の Memo1 にアクセス
するには、ただ単に

Memo1.LoadFromFile(...);

とするだけです。これは

self.Memo1.LoadFromFile(...);

と同じことです。self は、自分自身のインスタンスを参照するものです。

self の意味は、オブジェクト指向のプログラミングに重要なものです。是非、理解
してください。


Yama  2006-11-15 23:25:43  No: 23922

丁寧な説明ありがとうございます。
おかげで何とか進んでいます。

>self の意味は、オブジェクト指向のプログラミングに重要なものです。是非、理解

Delphiもオブジェクト指向も深い理解なしにやってきて勉強不足を痛感しています。

いろいろやってもわからない下記を教えていただけませんか。

>TChildFrom(MDIChildren[0]).Memo1.LoadFromFile('...');

MDIChildren[0] の[ ]内のIndexをChildFormの起動後、
FormCreate(Sender: TObject); 内などで知る方法です。

また、下記のようにChildForm作成時、Captionを指定した場合、
子フォーム上部のCaption自体は正常に表示されているのですが、
子フォームのFormCreate(Sender: TObject); で、
Self.Captionを確認するとCaptionが変わっています。
FormCreateで、下記の設定Captionを見る方法はありせんか。

procedure TMainForm.sbClick(Sender: TObject);
var ChildForm: TChildForm;
begin
  ChildForm := TChildForm.Create(Self);
  ChildForm.Caption:='Child Form('+inttostr(Childcounter)+')';
  childForm.show;
end;

何度もすみませんが、よろしくお願いします。


うんと  2006-11-16 00:43:41  No: 23923

> MDIChildren[0] の[ ]内のIndexをChildFormの起動後、
> FormCreate(Sender: TObject); 内などで知る方法です。

例を示します。

親フォーム

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    NewChild1: TMenuItem;
    procedure NewChild1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Unit2;

procedure TForm1.NewChild1Click(Sender: TObject);
begin
  TChildForm.Create(self);
end;

end.

---------

子フォーム

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TChildForm = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  ChildForm: TChildForm;

implementation

{$R *.dfm}

uses
  Unit1;

procedure TChildForm.FormCreate(Sender: TObject);
begin
  Caption := 'Child No.' + IntToStr(Form1.MDIChildCount);
end;

end.

-------

このコードで、親フォームのメニュー項目 NewChild1Click() を実行するたびに 
Unit2 の子フォームが作られますが、現在何番目なのかは作成直後の Caption に
表示されます。

> 子フォームのFormCreate(Sender: TObject); で、
> Self.Captionを確認するとCaptionが変わっています。

これは当然ですね。

ChildForm := TChildForm.Create(Self); 

FormCreate() は、コンストラクタの実行中に呼ばれます。ですから

ChildForm.Caption:='Child Form('+inttostr(Childcounter)+')';

これはまだ実行されていないのです。


Yama  2006-11-16 16:05:15  No: 23924

MDIChildCountでの表示確認しました。
ソースまで書いて頂いてありがとうございます。

複数あるChildFormのアプリ表示条件を保存して、再起動時個別条件で
表示出来るような方法がないかと悩んでいました。

各ChildFormをこのMDIChildCountで区別して、***.iniファイルへでも
保存するよう考えてみます。

最後にひとつ教えてください。
ChildFormにMemo1があったとして、

Procedure test;
begin
  memo1.lines.add('test');
end;

これはmemo1がないとエラーになります。
このようなProcedureで、フォーム名を指定してmemo1などを
使うにはどのような指定(型キャスト?)を行うのでしょうか。


うんと  2006-11-16 19:24:58  No: 23925

普通の手続きや関数には、暗黙の self がありませんので明示的に、インスタンス
を渡す必要があります。

Procedure test(frm: TChildForm);
begin
  frm.memo1.lines.add('test');
end;

として、この手続きを呼ぶ方が、self なり、TChildFrom(MDIChildren[0]) なり
をわたすようにしないとだめです。

時間に余裕がでたら、クラスや可視性、参照、などのオブジェクト指向プログラミング
を基礎から学ぶようにしてください。Delphi に限らず、他の多くの言語でも
応用が利くようになります。


Yama  2006-11-17 03:01:39  No: 23926

>Procedure test(frm: TChildForm);
>begin
>  frm.memo1.lines.add('test');
>end;
>として、この手続きを呼ぶ方が、self なり、TChildFrom(MDIChildren[0]) なり

実際には引数にして処理していたのですが、やはりそうですか。

>時間に余裕がでたら、クラスや可視性、参照、などのオブジェクト指向
>プログラミングを基礎から学ぶようにしてください。Delphi に限らず、他の多くの言語でも

実は、PascalはTrubo3からDelphiもVer1からで本もけっこうあるのですが、
こういう全体を俯瞰出来るようなで推奨の本はありませんか。
プログラミングバイブル4、6なども必要なTipsを調べる程度しか使っていません。  
まあ、近道などはないとは思っていますが。

ありがとうございました。  とても助かりました。とりあえず解決とします。
また、どうしても困ったときにはよろしくお願いします。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加