トップ回答者
SDIとダイアログベース

質問
-
Windows XP SP2の環境下でVisual C++ 6.0を使用しています。
今まで、ダイアログベースにてプログラムを作成していたのですが、参考にしている教科書によって、ダイアログベースになったりSDIになったりで、どうしたらよい物かと悩んでいます。
初歩的なプログラムは全てダイアログベースで作成可能だったのですが、使いたいボタンなどによってはSDIで書かれています。
SDIで書かれているプログラムをそのままダイアログベースで書いたら不都合あるのでしょうか?
また、SDIとダイアログベースは何が違うのかを、わかりやすく教えていただければと思います。
よろしくお願いいたします。
回答
すべての返信
-
ふつうの ウィンドウ も モードレス・ダイアログ もメッセージを処理するための
コールバック関数を定義しますよね。
(以下,それぞれ WindowProc, DialogProc と呼ぶことにする )
(注: ATL(WTL)やMFCを使っている場合は,
メッセージ・クラッカーと呼ばれている
BEGIN_MSG_MAP ~ END_MSG_MAP マクロのところ)
で,それら自作の関数内で,
メッセージを処理しなかったときのために,
デフォルトのウィンドウ・プロシージャがあらかじめ用意されいます。
WindowProc の方には,メッセージが直接やってきて,
処理しないものを デフォルトのものを呼び出して(DefWindowProc(,,,) )処理する形だけれど,
DialogProc の方には,
先にデフォルトのものが,親切にも,
いくつかのメッセージ(TABキーなど)を処理してくれて,
処理されなかった残りのメッセージがやってきます。で,
DialogProcで処理しなかった場合(FALSEとして戻り値で返す),
デフォルトのものに戻ったときに再度処理してくれる形になっています。
この仕組みの関係で,
Dialogの方へメッセージを送るには,
IsDialogMessage(,) を呼び出すことになっています。
簡単に書くと,
「DialogProcへのメッセージは,間引かれてやって来る」
って感じです。
ATL(WTL) や MFC のようなフレームワークとして提供しているものは,
PreTraslateMessage( ) という仮想関数を用意して,
それをオーバーライドすることで,
IsDialogMessage(,) を呼び出す前に,
間引きされてしまう前に,メッセージを処理することも可能なようになっています。
# 正確ではないかもしれません
メッセージ(MSG)が伝播していく簡単な流れを書くと,
[モードレス・ダイアログ の MSG の移動]
GetMessage
↓
(PreTranslateMessage)
↓
IsDialogMessage
↓
デフォルトのダイアログプロシージャ (of デフォルトのダイアログクラス)
↓
ユーザー定義のDialogProc関数
↓
デフォルトのダイアログプロシージャ (of デフォルトのダイアログクラス)
↓
(TranslateMessage)
↓
(DispatchMessage)
↓
繰り返し
[いわゆるふつうの ウィンドウ の MSG の移動]
GetMessage
↓
(PreTranslateMessage)
↓
TranslateMessage
↓
DispatchMessage
↓
ユーザー定義のWindowProc関数
↓
(デフォルトのウィンドウ・プロシージャ)
↓
(ユーザー定義のWindowProc関数)
↓
繰り返し
また,
ATL(WTL)やMFCで,
外枠をふつうの ウィンドウ で作成して(フレーム・ウィンドウといいます)
そのウィンドウのクライアント領域いっぱいに,
ダイアログ・ウィンドウ を広げて表示する形になっているのを
フォーム・ビュー といっています。
なので,そういうのと遭遇した時には,
内側がダイアログなんだと思えばいいです。
外側の(ふつうの)ウィンドウの PreTranslateMessage のオーバーライドの中で,
内側のダイアログ・ウィンドウの PreTranslateMessage を呼んで,
その中で,IsDialogMessage を呼んでいます。
その結果,内側の DialogProcコールバック関数に
メッセージが渡ります。
流れさえわかれば,
汎用的に書いてある他の人のコードを
どこをどのように変えればいいか,だいたいわかる筈です。
-
ありがとうございます。
分かったような分からないような…
まず、普通のウィンドウはSDIでモードレス・ダイアログがダイアログベースと考えたらよいのですよね?
僕が普段使っているのはMFCを利用しています。
(買った本がそこから入っているので、それ通りにやる事になれてしまいました。)
多分、MFCの事を十分に把握してから、使用しなければならないと思うのですが、買った参考書通りにやっていくとどうしてもその部分を無視してしまっています。
さて、流れとか専門的な事はよく分からなかったのですが、かいつまんで言えば、SDIの機能の一部としてダイアログベースがあるってことですか?
>内側がダイアログなんだと思えばいいです。
>外側の(ふつうの)ウィンドウの PreTranslateMessage のオーバーライドの中で,
>内側のダイアログ・ウィンドウの PreTranslateMessage を呼んで,
>その中で,IsDialogMessage を呼んでいます。
>その結果,内側の DialogProcコールバック関数に
>メッセージが渡ります。
の文章から、そう思いました。
すると、単純に考えて、SDIがダイアログベースを含んでいる物なら、ダイアログベースで書かれているプログラムはSDIで同じように書いても問題ないけど、SDIで書かれているものはある種の変更がないとダイアログベースで書けないという事ですか?
いついつ、大小関係で考えてしまうのですが、このように思えばよいのでしょうか?
-
さりゅー さんからの引用 まず、普通のウィンドウはSDIでモードレス・ダイアログがダイアログベースと考えたらよいのですよね?
僕が普段使っているのはMFCを利用しています。
MFCを使っている場合は,上記のメッセージの流れを隠蔽しているので,
利用するクラスを変えることに相当しますね。
さりゅー さんからの引用 SDIで書かれているものはある種の変更がないとダイアログベースで書けないという事ですか? 上のメッセージの流れでわかるように,要するに,
ダイアログベースにするには,
どこかで IsDialogMessage(ダイアログのハンドル, MSGへのポインタ) が入っていないと
ダイアログにメッセージがやってこないですね。
いきなりMFCの場合だとわかりづらいので,
一度,生Win32API呼び出しで,作成して比べてみると
仕組みがわかりやすいと思います。
-----
フォームビューの話を出したのは,
中身(ビューの部分)だけ入れ替えればいいだけなので,
コードをテストするには楽だと思ったので書いたんですが,
かえってややこしくしましたかね。
[追記]
ダイアログでやりたいと言うのは,
要するに,ダイアログリソースを利用してやりたいということですよね?
例えば,
ドキュメント/ビューを採用している SDIアプリ ならば,
ビューを作成するクラスを CView から CFormView に変えれば,
ダイアログリソースを使えるので,楽できるという話です。
(アプリケーションの雛形を作成するウィザード時に
生成されたクラス のところで,ビュー の基本クラスを CView から CFormView に換えておく)
-
yayadon様、Azulean様
ありがとうございます。
この週末に色々試したりしました。
自分の勉強不足(クラスのマスターなど)の弱点が浮き彫りになりました。
私の場合、VisulaC++を使う前は、C++buliderを使っていました。
しかし、VisualC++に入ると、その似ている方法として、ダイアログベース(ダイアログソース)が最も近い気がして、気楽に使っていました。(参考図書もそこから入っていたので…)
すると、SDI/MDIとの違いに躓き、何が何だか分からなくなっていました。
今は、ぼんやりですが何となく意味の違いが見いだせた気がします。
完全解決ではないのですが、皆さんの意見を参考にもう少し自分でやってみて、細かい問題点を探っていこうと思います。
今回は解決とさせていただくのですが、多分きっと分からない事が出ると思うので、その時はご指導いただければ幸いです。
-
ドキュメント/ビュー アーキテクチャ を使わない場合は,
ATL/WTL でやった方が楽かもしれません。
http://home.att.ne.jp/banana/akatsuki/doc/atlwtl2/view12/index.html
など求めているものに近いんじゃないかと思います。
SDIなんだけど,
内側をダイアログ・リソースを利用してやれます。オススメ