DialogBox とスレッドについて

[戻る]
サウロ 2010/05/24(月) 15:38:00
環境:
WinXP SP2
VC2005 Standard

アプリケーションにダイアログボックスを組み込みたいのですが、
フォントによって大きさが変わってしまします。

ダイアログボックスの大きさは固定にしたいので、
別に自分でダイアログボックスと同じような子ウィンドウをつくろうかと考えています。

参考にDialogBox関数の挙動を調べていたのですが、
DialogBoxを呼び出すとそのスレッド(ここでははwWinMainCRTStartup)
は例えばダイアログのOKボタンを押すまで止まっています。

ところが、ダイアログが出ている状態でメインウィンドウを最小化して元に戻すような処
理をした場合、case WM_PAINT: でブレークさせるとVCのスレッドウィンドウには
wWinMainCRTStartup が表示されます。

DialogBox関数を呼んでいるところでSleep(10000) などとやっておいても、Sleep中には
WM_PAINTのところにはこないので不思議に思っています。

Windows ではどのような処理がされているのでしょうか?
また、私が考えているような子Windowを作成することは可能でしょうか?
よろしくお願いします。

仲澤@失業者 2010/05/24(月) 16:50:36
>フォントによって大きさが変わってしまします。

どういった症状なのか今一理解できないのですが、一般にDLGリソースに
フォントの設定がしてあれば、「画面のプロパティ」等でフォントを変えても
コントロールには影響がないと思うのですが。どうなんでしょう。

また、動的にDLG内の全てのフォントを変更した場合でもSetWindowPos()すれば
DLGサイズやコントロールのサイズは制御可能ですよね。

>参考にDialogBox関数の挙動を調べていたのですが、

Win32SDKのDialogBox()は、モーダルDLGを表示します。
モーダルDLG表示中は、当該のアプリケーション内の表示中のモーダルDLG
以外には入力(マウス、キー)フォーカスが移動しません。
どうやって、親ウインドウを最小化したのでしょうか。

>別に自分でダイアログボックスと同じような子ウィンドウをつくろうかと考えていま
す。

モードレスっぽいポップアップウインドウを作成するのは簡単です。
しかし、モーダルDLGと同等の動きをするウインドウを作成するのは
(MFCの実装を見ると)なかなか大変なようです。

maru 2010/05/24(月) 17:04:24
> フォントによって大きさが変わってしまします。
> ダイアログボックスの大きさは固定にしたいので、
どんなフォントでも、ダイアログボックスの大きさを固定にしたいということでしょう
か?
ダイアログボックスの大きさが表示する文字とは無関係なサイズになるのはユーザに
とってメリットにはならないと思いますがどうでしょう?

> 別に自分でダイアログボックスと同じような子ウィンドウをつくろうかと考えていま
す。
サイズを固定にするのでしたら、わざわざこんなことをしなくてもダイアログボックス
のフォントを指定してしまえばいいだけでは?

> また、私が考えているような子Windowを作成することは可能でしょうか?
可能とは思いますが、大きさを固定にする為だけにそこまでやるのはお勧めしません。
まぁCreateWindow関数を使用すれば、任意のオーバーラップウィンドウ、ポップアップ
ウィンドウ、子ウィンドウを作成することは出来ますが。

サウロ 2010/05/24(月) 17:09:30
>一般にDLGリソースに
>フォントの設定がしてあれば、「画面のプロパティ」等でフォントを変えても
>コントロールには影響がないと思うのですが。

このアプリをインストールするハードが未確定で、ハードによるフォントの大きさのぶれ
が気になります。

>どうやって、親ウインドウを最小化したのでしょうか。

すいません、最小化ではないですね。
WM_PAINT が送られるよう、別のウィンドウで隠したのち、タスバーの該当場所をクリッ
クしてもとに戻しました。

>モーダルDLGと同等の動きをするウインドウを作成するのは
>(MFCの実装を見ると)なかなか大変なようです。

わかりました。ありがとうございます。

>SetWindowPos()すれば
>DLGサイズやコントロールのサイズは制御可能ですよね。

このAPIは知りませんでした。
こちらの方法でやってみようと思います。

ただ、DialogBox 関数がどうやってWindowsに扱われるのかが気になります。
わかりやすく解説してくれるサイト等ありましたら、ご教授ください。

サウロ 2010/05/24(月) 17:22:06
回答ありがとうございます。

>ダイアログボックスの大きさが表示する文字とは無関係なサイズになるのはユーザに
>とってメリットにはならないと思いますがどうでしょう?

ダイアログボックスに貼り付ける画像の問題です。
フォントは最終的には固定になりますが開発中に大きさを変えることがありますし、
ダイアログウィンドウの大きさをぴったり画像に合わせなくてはならないので微調整して
もなかなか合いません。
仲澤さんの回答にあるSetWindowsPosでやってみようと思います。

>CreateWindow関数を使用すれば、任意のオーバーラップウィンドウ、ポップアップ
>ウィンドウ、子ウィンドウを作成することは出来ますが。

ソースコード内の既存のDialogBoxの呼び出しをすべて置き換えたいと思っています。
全く同じ挙動をするようなウィンドウを作るのは難しいようなので質問しました。

maru 2010/05/24(月) 17:49:47
> このアプリをインストールするハードが未確定で、ハードによるフォントの大きさの
ぶれ
> が気になります。
だからこそ、ダイアログボックスはフォントサイズに依存するんでしょ。

> ダイアログボックスに貼り付ける画像の問題です。
最初からそう言ってくれればいいのに。
ダイアログボックスの内部に画像しか無いのであれば、仲澤さんの回答にある通り
SetWindowsPosが適当でしょう。
ダイアログボックスの内部に他の要素がある場合、それらのコントロールの位置も
プログラムで計算して微調整する必要があります。

> ただ、DialogBox 関数がどうやってWindowsに扱われるのかが気になります。
基本的には親ウィンドウをディセーブルにした子ウィンドウですね。
DialogBox()は親ウィンドウをディセーブルにして、リソースからダイアログテンプ
レートを読み出して子ウィンドウを生成、メッセージループを回してEndDialog()で
でダイアログボックスの終了されたら、メッセージループを終了し、親ウィンドウ
をイネーブルにしてEndDialog()の値を返す。

って、よくよく見ればMSDNに書いてあるじゃん。orz
http://msdn.microsoft.com/ja-jp/library/cc410759.aspx
「DialogBox マクロは、CreateWindowEx 関数を使ってダイアログボックスを作成しま
す。その後、WM_INITDIALOG メッセージをダイアログボックスプロシージャへ送信しま
す( テンプレートに DS_SETFONT または DS_SHELLFONT スタイルが指定されている場合
は、WM_SETFONT メッセージも送信します)。そして、( テンプレートに WS_VISIBLE 
スタイルが指定されているかどうかにかかわりなく)ダイアログボックスを表示し、オ
ーナーウィンドウを無効にし、独自のメッセージループを開始して、そのダイアログボ
ックスに関するメッセージの取得とディスパッチを行います。

ダイアログボックスプロシージャが EndDialog 関数を呼び出すと、DialogBox はそのダ
イアログボックスを破棄し、メッセージループを終了し、オーナーウィンドウを有効に
します( 以前に有効になっていた場合)。そして、ダイアログボックスプロシージャ
が EndDialog 関数を呼び出した際に指定した nResult パラメータの値を返します。」

maru 2010/05/24(月) 18:23:09
さて、DialogBox()の説明を終えたところで、最初の疑問について考察。

> DialogBoxを呼び出すとそのスレッド(ここでははwWinMainCRTStartup)
> は例えばダイアログのOKボタンを押すまで止まっています。
DialogBoxを呼び出すとその内部でEndDialog()を呼び出すまで返ってこないので、
止まって見える。

> ところが、ダイアログが出ている状態でメインウィンドウを最小化して元に戻すよう
な処
> 理をした場合、case WM_PAINT: でブレークさせるとVCのスレッドウィンドウには
> wWinMainCRTStartup が表示されます。
しかし、ダイアログが出ている状態ではダイアログ側でメッセージループが回って
いるので、親ウィンドウにもメッセージを処理する機会が与えられる。そこで、描
画要求(WM_PAINTメッセージ)が発生すると、親ウィンドウのメッセージループで
描画処理が呼び出される。

> DialogBox関数を呼んでいるところでSleep(10000) などとやっておいても、Sleep中に> WM_PAINTのところにはこないので不思議に思っています。
Sleepは何もやらない関数であり、メッセージループが回っていないので描画要求を
受け付けることが出来ない。

以上の解釈でいかがですか。

サウロ 2010/05/24(月) 18:47:28
[[解決]]
なるほど、
詳しい解説ありがとうございました。

古いスレッドには追加発言できません。