- ベストアンサー
ダイアログの表示、非表示の切り替えについて
- ダイアログの表示と非表示を切り替える方法について
- ウィンドウの非表示状態から表示状態に切り替える方法について
- ダイアログの非表示と表示を切り替える方法について
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
モーダルだとなぜいけないかを書いてなかったですね。 別にMFCだからとかそんな理由ではないですよ。 スレッドが止まるとかいうことでもないですし。 理由:dlg.DoModal()の時点で、CMainFrame::OnKNew()の処理が止まっているから。 ここでさらなる疑問が出るでしょう。 なぜ、 CMainFrame::OnKNew()を複数回呼び出すと、処理が止まっているにもかかわらず新しいダイアログが表示されてしまうのか? 理由:CMainFrame::OnKNew()は止まっていると言ったが、 プログラム中にあるメッセージループはどこかで動いているからメッセージは受け取れる。 そして、最初と同様、dlg.DoModal()を呼び出すと処理は停止します。 ロックがかかっていても、メッセージを受け取れるというのは、当然といえば当然です。 描画のメッセージが受け取れなくなったら親ウィンドウの描画ができなくなってしまいますからね。 では、どうして呼び出し中の関数があるのにそんなことが可能なのでしょうか? 理由:CやC++の関数は、再帰呼び出しが可能だから です。 つまり、モーダルウィンドウが表示されている間でも、メッセージはシステムから(若しくは今回のように明示的にでも)飛んできます。 PostMessageで送られてきたものはメッセージキューにためられた後DispatchMessageから、SendMessageで送られたものは直接ウィンドウプロシージャが呼び出されます。 このとき、前回コールされて止まったままとなっている CMainFrame::OnKNew()の呼び出し元となっているウィンドウプロシージャはスタックにためられます。 前回の呼び出し分がスタックにためられるから、後から呼ばれたプロシージャは何事もなかったかのように動作することが出来ます。 ということで、 CInput dlg; がいくつも存在するかのように見える状態は、異常ではありません。スタックに詰まれていることになります。 実際には、オブジェクトが存在するアドレスが違います。 アドレスが違うということは、区別することも可能ですよね。 メンバ変数を上手く使えば確認できますよ。 ちなみに、スタックには限度というものがあるので。あまりやりすぎるとスタックオーバーフローで落ちます。 #確認したいのであれば、メッセージハンドラの中で同じメッセージSendすればすぐにできますよ(^^;
その他の回答 (2)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>再帰ですか。これ始めて知ったとき凄く不可解でした。 >だって、肉屋はどこ?八百屋のとなり。八百屋はどこ? >肉屋のとなり。以下この繰り返し。みたいに感じたから。 たしかに、いいサンプルがないと分かりづらいですね。 概念的にはバックトラック、いわゆる”しらみつぶし”ですね。 よく例に出されるのがチェスのナイトが一筆書きですべての64マスをまわれるかとか。 個人的には、ドライブのフォルダに含まれるファイルを順に列挙していくようなプログラムを作るのが分かりやすいと思います。 >メッセージSendする???良く分かりませんが、今となっては必要ないかな。。。 Windowsプログラムを組む上で、PostとSendの違いは重要です。 ちなみにPostとは、PostMessage()でメッセージ送信、SendとはSendMessage()でメッセージ送信です。 ここのサイトでも、よく使い方を間違ってる人を見ます。 たとえば、下の2つ、落ちずに1000000回メッセージが送られるのはどっち? ということです。 CMyWnd::OnLButtonDown(UINT nFlags, CPoint point) { if(m_iCount < 1000000 ) { SendMessage(WM_LBUTTONDOWN, 0, 0); m_iCount++; } } CMyWnd::OnLButtonDown(UINT nFlags, CPoint point) { if(m_iCount < 1000000 ) { PostMessage(WM_LBUTTONDOWN, 0, 0); m_iCount++; } } ちなみに、m_iCountはCMyWndのメンバ変数で、コンストラクタで初期化しておいてくださいね。
お礼
ようやくやってみましたが、どちらも落ちませんでした。 理屈上落ちるのは、PostMessageだと思いますが、どうでしょうか?
- taka_tetsu
- ベストアンサー率65% (1020/1553)
モーダルで作ることがNGです。 モードレスで作りましょう。 いちばん簡単なのは、あらかじめ非表示作っておき、 非表示にしておきます。 そして、タスクトレイからメッセージがきたら表示してあげる、ボタンが押されたら非表示にする、とすれば問題ないでしょう。
お礼
回答ありがとうございます。 モーダルで一応作ってみました。 ポインタがNULLかどうかの判定でうまく行きました。 と思ったらモーダルはNGとのことなので、モードレスに変更しました。 ところが、モーダルの作り方が分からないし、起動時に作っておいて非表示する方法がわからない。ということで色々やってみてようやくで出来ました。 以上報告です。
お礼
>モーダルだとなぜいけないかを書いてなかったですね。 これ聞きたかったけど躊躇してました。察していただき感謝です。 >なぜ、 CMainFrame::OnKNew()を複数回呼び出すと、処理>が止まっているにもかかわらず新しいダイアログが表示さ>れてしまうのか? まさにこれが疑問でした。 >理由:CやC++の関数は、再帰呼び出しが可能だからです。 再帰ですか。これ始めて知ったとき凄く不可解でした。 だって、肉屋はどこ?八百屋のとなり。八百屋はどこ?肉屋のとなり。以下この繰り返し。みたいに感じたから。 >前回の呼び出し分がスタックにためられるから、後から呼ばれたプロシージャは何事もなかったかのように動作することが出来ます。 そうだったのですか。ようやく納得です。 >メンバ変数を上手く使えば確認できますよ。 これは確認できました。 >#確認したいのであれば、メッセージハンドラの中で同じメッセージSendすればすぐにできますよ(^^; メッセージSendする???良く分かりませんが、今となっては必要ないかな。。。 #今回の話は凄く面白かったです。また、お願いします。m(__)m