ページ 11

ウインドウの「親子」関係について

Posted: 2006年7月23日(日) 04:30
by jacoby
 メインのウインドウ上に貼り付けたボタンをクリックすると
そこから、(このメインウインドウを親とする)モーダルダイアログを開き、
そのモーダルダイアログ上のボタンをクリックすると
(このモーダルダイアログを親とする)メッセージボックスが表示されるという
プログラムを書いたのですが、ウインドウの親子関係でうまく分からないこと
があります。

メインのウインドウ
      ↓
  モーダルダイアログ
       ↓
   メッセージボックス


 メインウインドウからモーダルダイアログを出した段階で
やっぱりやめた、と、そのモーダルダイアログの閉じるボタンを
押して消した場合、ダイアログの親であるメインウインドウが再び
アクティブになります。ここまでいいのですが、
 一旦、モーダルダイアログから更にメッセージボックスを
表示させると、その後(メッセージボックスに応答してそれを消してから)、
モーダルダイアログを閉じた時、
メインウインドウは自動的にアクティブになりません。

メインのウインドウ
      ×
      ↑
  モーダルダイアログ
       ↑
   メッセージボックス

モーダルダイアログを閉じるとき、初めはそのダイアログのクローズ・イベントである
Dialog1_QueryClose()のなかで「EndDialog(hDialog1)」と書いていたのですか
これを書くと、モーダルダイアログが消えてからメインのウインドウまで
たて続けに消えてしまい、プログラム自体が終了してしまいます。
それでEndDialogは書かずにおいてみたのですが、今度は
上に書いたように、メインウインドウがアクティブにならなくなる。

 この辺の親子のつながりがよく分からず、悩んでいます。

メインのウインドウ
      ↑
  モーダルダイアログ
        ↑
   メッセージボックス

 このように、それぞれを閉じた時、元を辿って親を順にアクティブにするには
どうすれば良いのでしょうか?


---------------------------------------------
下にプログラムを。
AB4.24で実行しました。

 まずRADでメインのウインドウとダイアログ1(モーダルダイアログ)を
作り、

 メインウインドウに[Dialog1]、[Close]という二つのボタンを
貼り付ける。
([Dialog1]をクリックでダイアログ1を開く。[Close]でメインウインドウを
閉じる。)

 それからDialog1というモーダル・ダイアログを作り、
[OK]、[CANCEL]という二つのボタンを貼り付ける。
([OK]でメッセージボックスを表示し、[CANCEL]でダイアログを閉じる。)

返信@yu0627

Posted: 2006年7月23日(日) 10:42
by yu0627
 モーダルダイアログのDestroyイベントの中に以下のコードを仕込んでください。

コード: 全て選択

SetActiveWindow(hMainWnd)
 多分、僕の経験上これで直ると思いますが。

レスありがとうございます。

Posted: 2006年7月24日(月) 18:25
by jacoby
 yu0627さん、レスありがとうございます。

教えていただいた、
「SetActiveWindow(hMainWnd)」
で、しっかりと直りました。
 ありがとうございました。


 ただ、正直なとこまだ少し引っかかっているんです。

 例えば、上のプログラムのモーダルダイアログから
メッセージボックスを「出さず」にそのまま閉じた時は
SetActiveWindow(hMainWnd)が無くても
メインウインドウはアクティブに戻ってきます。
つまりこのときは、既にアクティブなメインを
「もう一度アクティブにする」感じになるのでは
ないかと思います。

 もちろん、だからといって動作そのものに影響はない
ので別にどうだとも思うのですが、元々のとこの疑問、
「なぜメインのウインドウからダイアログを開き、
更にそこからまたダイアログ(ここではメッセージボックス)を
一度開くと、元あったはずの親子の関係が
途切れてしまうように見える動作が起こるのか」ということが
分からないままなんです。

 モーダルダイアログを閉じる時、

コード: 全て選択


'
' ●Dialog1 閉じる
'
Sub Dialog1_QueryClose(ByRef cancel As Integer)
' ↓ここにEndDialogを書くと、メインのウインドウまで消えてしまい
'        プログラムが終了してしまう
EndDialog(hDialog1,0)

End Sub
このように書くとメインのウインドウまで消えてしまうのも
何故なのか分からないのですが、もしかして、EndDialogプロシージャの中でも
DestroyWindow命令があり、更にこのDialog1_QueryCloseサブの
実行後にもDestroyWindow命令が控えていて、それで二重で消えている
のかと思い、とりあえず試しに、

コード: 全て選択


'
' ●Dialog1 閉じる
'
Sub Dialog1_QueryClose(ByRef cancel As Integer)
' ↓ここにEndDialogを書くと、メインのウインドウまで消えてしまい
'        プログラムが終了してしまう
EndDialog(hDialog1,0)
cancel=TRUE

End Sub
と「cancel=TRUE」と入れてみました。
そうすると今度はメインのウインドウまで消えることはなくなったの
ですが、やはりメインがアクティブにはなってくれません。

 「DialogBox()」と「EndDialog()」は必ず一対に書かなければ
ならないのか、それとも必ずしもそうではないのか、ということも
そうなのですが、
 ウインドウからダイアログを開き、更にまたそこからダイアログを開き、
更にまた、ということはウインドウプログラミングでは頻繁に
あることだと思うので、このあたり出来ればハッキリと分かりたい
と思っています。

返信@yu0627

Posted: 2006年7月24日(月) 20:28
by yu0627
QueryCloseイベントの使い方の関係上、その中にEndDialogを書くのはまずいと思います。
Callback.sbpをテキストエディタで開き、その中にEndDialogがあります。

コード: 全て選択


Sub EndDialog(hWnd As HWND, lResult As Long)
	EnableWindow(GetWindow(hWnd,GW_OWNER),1)
	DestroyWindow(hWnd)
	PostMessage(0,WM_QUIT,lResult,0)
End Sub
 とりあえず、ウインドウオーナーを有効にするコードは入っていますが、アクティブにするコードは入っていないようです。多分これが原因だと思います。ですので、ダイアログのDestroyイベントの中に昨日書いたコードを仕込んで置いてください。また、DestroyWindow関数はウインドウを破棄する関数です。これを二度実行すると、何が起こるか確かにわかりません...。
 とりあえず、QueryCloseイベントはウインドウが閉じられようとして破棄される前に呼び出されますので、その中にEndDialogを書くことは絶対不可だと思います。

レスありがとうございます。

Posted: 2006年7月24日(月) 22:55
by jacoby
 とりあえず、QueryCloseイベントはウインドウが閉じられようとして破棄される前に呼び出されますので、その中にEndDialogを書くことは絶対不可だと思います。
 DialogBox()とEndDialog()を必ず対にさせなければならないのかと
EndDialog()の置き場所を探して、QueryCloseイベントに置いたのですが
(「閉じる」ボタンを押した時にも通る所ということで)、
「閉じる」ボタンを押した時など、既に破棄されるコースに乗っている場合は
その必要は無いんですね。

それから、元々の疑問についても、
とりあえず、ウインドウオーナーを有効にするコードは入っていますが、アクティブにするコードは入っていないようです。多分これが原因だと思います。
EndDialogの中身も見せて頂いて、納得しました。

 DestroyイベントにSetActiveWindow(hMainWnd)を仕込みたいと思います。

 重ねてのレス、EndDialog()の中身の解説、ありがとうございました。
またよろしくお願いします。