こんばんわ。
Windowsプログラムを始めたばかりのものです。
WindowsXP, VC++.net, SDKです。
CreateWindow関数でエディットコントロールを20個作りました。
親ウインドウのサイズが変わっても常に親ウインドウの中央に表示したいんです。
case WM_PAINT:
BeginPaint(hWnd, &ps);
//MessageBox(hWnd,(LPCSTR)前,(LPCSTR)前,MB_YESNO); ---1
SetEditCenter(hWnd);
//MessageBox(hWnd,(LPCSTR)後,(LPCSTR)後,MB_YESNO); ---2
EndPaint(hWnd, &ps);
break;
void SetEditCenter(HWND hWnd)
{
GetClientRect(hWnd, &rc);
for(i = 0; i <= 19; i++){
// ここで20個のエディットコントロールのx, y座標を順番に計算しています。
SetWindowPos(hEWnd[i], HWND_TOP, x, y, NULL, NULL, SWP_NOSIZE);
}
}
1と2のメッセージボックスをコメントアウト
プログラム起動
望み通り中央に配置される
親ウィンドウのサイズ変更
エディットコントロールが表示されない ---A
2のみコメントアウト
プログラム起動時
メッセージボックス表示
エディットコントロールが中央へ
またメッセージボックスが表示される ---B
親ウィンドウのサイズ変更
メッセージボックス表示
エディットコントロールが中央へ
またメッセージボックス表示 -----------C
1と2両方コメントアウトしない
2のみコメントアウトの動きの中でエディットコントロールが中央に
表示された後続けて2回表示される -----D
Aももちろんどうしてだろう?と思うんですが
B, C, Dはさらに混乱しています _ _#
Window作成時などでどこか設定が悪いのでしょうか?
質問の内容が伝わりにくいかもしれませんが
どなたかご教授お願いいたします。
> case WM_PAINT:
ここが違う。
WM_PAINT でなく WM_SIZE で SetEditCenter(hWnd); を呼ぶ。
SDK ならまず、「よく使う」Windows メッセージを覚えておくといい。
エディットウィンドウを動かすタイミングはWM_PAINTじゃなくてWM_SIZEじゃないかな。
WM_PAINT : ウィンドウに再描画領域があると送られる
WM_SIZE : ウィンドウのサイズが変更した時に送られる
あと、void SetEditCenter(HWND hWnd)のxとyって何でしょう?
GetClientRect()で求めた幅と高さからエディットウィンドウの幅と高さを引いて
2で割れば中央に表示する為のの座標が出ます。
それだけです。
エディットウィンドウのサイズを変更しないならDeferWindowPos()等を使った方が
いいかな。
BeginDeferWindowPos()
DeferWindowPos()
EndDeferWindowPos()
の3つを参照してください。
あと、MessageBoxをWM_PAINT内で読んでしまうと
MessageBoxが表示されていた領域が無効化されて
またWM_PAINTが呼ばれてしまうと思います。
WM_PAINTがどういうときに呼ばれるのかわかっていれば、
WM_PAINTの処理内でMessageBoxを表示すべきでないのはわかると思います。
WM_PAINTの所を通ったことが確認したいのであれば、
TRACEを使ってアウトプットウインドウに表示するようにしてDebugビルドして
IDEから動かしてみた方が良いと思いますよ。
WM_SIZE で SetEditCenter() を呼んだら一発で解決しました。
お恥ずかしい限りです。
>あと、void SetEditCenter(HWND hWnd)のxとyって何でしょう?
エディットコントロールを20個作ったのですが
そのうち10個が120*20 ------A
後の10個が70*20 -----------B
なんです。
Aを縦に5個、次の列にBを縦に5個、またA、そしてB
というような感じで配置しました。
この20個のコントロールがクライアント領域の中央に表示したかったので
SetEditCenter()で
for(i = 0; i <= 19; i++){
switch(i){
case 0:
case 1:
case 2:
case 3:
case 4:
x = (rc.right - 400) / 2;
// 400 = 120 + 5(余白) + 70 + 10(余白) + 120 + 5(余白) + 70
break;
・
・
・
}
switch(i){
case 0:
case 5:
case 10:
case 15:
y = (rc.bottom - 120) / 2;
// 120 = 20 + 5(余白) + 20 + 5(余白) + 20 + 5(余白)+ 20 + 5(余白) + 20
break;
・
・
・
}
SetWindowPos(hEWnd[i], HWND_TOP, x, y, NULL, NULL, SWP_NOSIZE);
}
としていました。
これだと一つのエディットコントロールの座標を計算しては
移動、また次のを計算して移動となりますが
教えていただいた
BeginDeferWindowPos()
DeferWindowPos()
EndDeferWindowPos()
を使うと先に20個の座標を求めておいてEnd~()で
一斉に移動ということなんですね。
大変勉強になりました。ありがとうございます^-^
>TRACEを使ってアウトプットウインドウに表示するようにしてDebugビルドして
>IDEから動かしてみた方が良いと思いますよ。
ご迷惑でなければもう少し具体的にお教え願えませんか?
申し訳ありません。
御三方、ご教授ありがとうございました。
いや、MSDNでTRACEを調べれば一発だと思うんですが。
TRACEは、IDEのアウトプットウインドウにデバッグメッセージを出すための関数です。
ただし、TRACEはDebugモードでビルドしないと動作しないようになっています。
ですから、Debugモードでビルドしてと書いています。
IDEから実行しないとOutputウインドウに出てこないと思ったのでそうかいています。
デバックもに太というフリーソフトがあるのでこれで見てみる手もありますね。
いずれにせよ、WM_PAINT内でMessageBoxを出すのはまずいのでデバッグのやり方を
変えないと駄目です。
MessageBoxを出してやるデバッグ方法も良くやりますけれど、
TPOを考えて使わないとハマリますよ。
確か、リリースモードでもアウトプットウインドウにメッセージを出すための
関数もあったと思いますが、忘れました。
多分、TRACEも最終的にはこれを呼んでいるんでしょうけれど。
すでに「解決」となっていますが。
>確か、リリースモードでもアウトプットウインドウにメッセージを出すための
>関数もあったと思いますが、忘れました。
OutputDebugString ですね。
TRACE は MFC でしか使えません(多分)。
>TRACE は MFC でしか使えません(多分)。
ヘルプで検索してみましたが .(ドット)が出てきて
よく分かりませんでした。
OutputDebugString で文字列を出力するのは出来ました。
今までデバックというものを全く知らないというか
使わなかったのですが変数の中身に何が入っているかが
分かって感動的でした。(大げさかもしれませんが・・・)
これからはメッセージボックスはやめて
デバックモードで実行しますね!!
色々と勉強させていただきありがとうございました。
質問というより 感想のようになってしまって申し訳ありません。