OnResizeイベントの発生について

解決


tos  2004-11-10 23:09:05  No: 11701  IP: [192.*.*.*]

皆さんこんにちは。

OnResizeイベントの発生時期に関してなのですが、
下記に様な2つのフォームがあり(TForm2にはTMainMenuが追加されています)、
1.Form1のButton1Click()によって、TForm2のインスタンスの生成及びShowメソッドを呼び出す。
2.Form1のButton2Click()により、TForm2のインスタンス破棄を行う。
とした場合、TForm2のOnDestroyイベントの発生の後に、TForm2のOnResizeイベントが発生します。

ところが、TForm2にあるTMainMenu削除すると、上記を同じ手順で行っても
TForm2のインスタンス破棄した場合に、TForm2のOnDestroyイベントのみが発生します。
こちらの動きが正常だと思うのですが、TMainMenuの有る無しでこのような動きの違いが
発生するものなのでしょうか? それとも、私の環境だけの特殊な動きなのでしょうか?

環境は、Window's 2000 SP1、Delphi7です。

-----------------------------------------------------------------------------------------------
Unit1.pas

procedure TForm1.Button1Click(Sender: TObject);
begin
  MyForm2 := TForm2.Create(self);
  MyForm2.Show;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  MyForm2.Free;
end;

-----------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
Unit2.pas
procedure TForm2.FormResize(Sender: TObject);
begin
  ShowMessage('resize');
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  ShowMessage('destroy');
end;
-----------------------------------------------------------------------------------------------

編集    削除
@っしー  2004-11-11 00:40:31  No: 11702  IP: [192.*.*.*]

そういう使用だと思います。(確認しました)

で、

procedure TForm2.FormDestroy(Sender: TObject);
begin
  Self.OnResize := nil;  //ココを追加
  ShowMessage('destroy');
end;

で、Destory時にResizeのイベントを起こさないようにできます。

@っしー

編集    削除
@っしー  2004-11-11 00:41:24  No: 11703  IP: [192.*.*.*]

すいません誤字です。

(誤)そういう使用
(正)そういう仕様

編集    削除
tos  2004-11-11 02:57:37  No: 11704  IP: [192.*.*.*]

@っしーさん、ありがとうございます。

とりあえず教えていただいた方法で解決なのですが、よろしければもう少し教えてください。

勘違いしているのかもしれませんが、私はOnDestroyが実行されたら、
インスタンスはもう破棄されているものと思っていました。
しかし、OnDestroy実行の後にOnResizeイベントが起こるということは、
OnDestroyイベントが実行された後にも、インスタンスは生きているということでしょうか?
(まあ、OnResizeイベントが実行されるということは、生きているということなのでしょうが、いまいち釈然としないもので。)

また、じゃあインスタンスはいつ破棄されるのでしょうか。

編集    削除
@っしー  2004-11-11 03:11:30  No: 11705  IP: [192.*.*.*]

あんまり詳しくないので恐縮なのですが、、、

今回の場合は、Form2にMainMenuがあるので、Form2のDestroy時に、MainMenuが破棄されて、結果、フォームサイズが変わったということではないでしょうか?

Form1にボタンを追加して、Form2(MyForm)がインスタンス化されているかどうか、チェックしてみてはどうでしょう?

procedure TForm1.Button3Click(Sender: TObject);
begin
  if Assigned(MyForm2) then
    ShowMessage('インスタンス化されています')
  else
    ShowMessage('インスタンス化されていません');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  MyForm2.Free;
  MyForm2 := nil;  //この行も追加しました。
end;

編集    削除
tos  2004-11-11 18:41:31  No: 11706  IP: [192.*.*.*]

>Form1にボタンを追加して、Form2(MyForm)がインスタンス化されているかどうか、チェックしてみてはどうでしょう?
を行うと、「インスタンス化されていません」と表示されます。

ただ、MyForm2はインスタンスへの参照を保持しているだけなので、
インスタンスが有効かどうかは無関係だと思います。
また、Assinged関数は、その変数がnilかどうかだけを調べるようなので、
procedure TForm1.Button2Click(Sender: TObject);
begin
//  MyForm2.Free;  <-削除
  MyForm2 := nil;
end;

として、Button2をクリックした後、Button3をクリックしても、
「インスタンス化されていません」と表示されます。
(MyForm2がnilなので)
しかし、当然Form2のインスタンスは有効です。
ただし、MyForm2はnilなので2度とForm1からMyForm2には
アクセスできませんが。

Button2クリックを以下のように変更して実行した後、
procedure TForm1.Button2Click(Sender: TObject);
begin
  MyForm2.Free;  
//  MyForm2 := nil;  コメントアウト
end;

新たな下記のButton4のクリックを実行すると例外が発生するので、
MyForm2のインスタンスが無効であるのは間違いないようです。
procedure TForm1.Button4Click(Sender: TObject);
begin
  MyForm2.Show;
end;

だから、OnDestroyイベントを実行した後からインスタンスを破棄する処理の間に、
割り込み?のような形で、OnResizeイベントが実行されてしまっているんですよね。
(詳しい動きがわからず、現象から推測しているだけなんですが)

編集    削除
@っしー  2004-11-11 19:42:39  No: 11707  IP: [192.*.*.*]

では、下記コードで試してみてください。
MyForm2の宣言部分がミソだと思います。
今回のコードは、既にMyForm2が生成されているときは、Showのみ実行します。

//-------------------------------------------------------------------
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}
var
  MyForm2: TForm2;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Caption := '生成・表示';
  Button2.Caption := '破棄';
  Button3.Caption := '確認';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(MyForm2) then
    MyForm2 := TForm2.Create(self);
  MyForm2.Show;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  MyForm2.Free;
  MyForm2 := nil;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  if Assigned(MyForm2) then
    ShowMessage('インスタンス化されています')
  else
    ShowMessage('インスタンス化されていません');

end;

end.

編集    削除
tos  2004-11-11 23:15:47  No: 11708  IP: [192.*.*.*]

すいません。ちょっと私が混乱してきたので確認させてください。

私の
「また、じゃあインスタンスはいつ破棄されるのでしょうか。」
という質問に対して、
@っしーさんが
「Form1にボタンを追加して、Form2(MyForm)がインスタンス化されているかどうか、チェックしてみてはどうでしょう?」
とアドバイス頂きました。

その後私が、
「MyForm2にAssignedを適用して判断しても、Form2(MyForm)がインスタンス化されているかどうかとは無関係に思います」
との旨の発言をしました。

そして、@っしーさんから
<では、下記コードで試してみてください。
<MyForm2の宣言部分がミソだと思います。
<今回のコードは、既にMyForm2が生成されているときは、Showのみ実行します。
と言われましたが、下記のコードを見てもMyForm2がnilなら、ただ新たにインスタンスを生成しているようにしか
見えません。
私は何か大きく勘違いしているのでしょうか?

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(MyForm2) then
    MyForm2 := TForm2.Create(self);
  MyForm2.Show;
end;

編集    削除
@っしー  2004-11-11 23:44:51  No: 11709  IP: [192.*.*.*]

※わたしも混乱してきました。(汗

>と言われましたが、下記のコードを見てもMyForm2がnilなら、ただ新たにインス>タンスを生成しているようにしか
>見えません。
>私は何か大きく勘違いしているのでしょうか?

その通りだと思いますが、、、
Form1からForm2を継承したフォームを幾つも生成させるには、自前で管理する機構を作る必要があるのではないのでしょうか?

説明不足で申し訳ございません。m(__)m
先に示した例は、Form1からForm2を継承したMyForm2の1つのみの例です。

編集    削除
@っしー  2004-11-12 00:59:10  No: 11710  IP: [192.*.*.*]

もし、Delphi7ProまたはEntをお使いであれば、マニュアルの「フォームの使い方」にある「ウィンドのようなモードなしフォームを作成する」の項目を参照してください。

その項目の最後には、
『(略)アプリケーションがフォームの追加インスタンスを必要とする場合は、各インスタンスごとに別のグローバル変数を宣言します。』

と記述されています。

編集    削除