親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
wasawasa
記事: 94
登録日時: 11年前

親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#1

投稿記事 by wasawasa » 11年前

こんにちは。いつもお世話になっております。
添付させて頂いたソースコードについて質問させていただきます。

親ウィンドウのサイズ変更に子ウィンドウを対応させるために
「ツールバーとステータスバーの座標とサイズをGetWindowRectで取得」
 ↓
「取得した情報を基にMoveWindowでサイズを変更する」
という記述をBase_WndProc.cppの37~47行目、MasterToolBar.cppの70~80行目、StateBar.cppの41~51行目、ModeZone.cppの37~50行目に書いて試したところ、ドラッグでのサイズ変更には対応できましたが最大化・最小化によるサイズの変更には対応できていませんでした。
そこで親ウィンドウの最大化・最小化によるサイズの変更に子ウィンドウを対応させたいと思いBase_WndProc.cppの48~58行目の記述を書いたところ、最大化・最小化の操作自体が不審な挙動を起こすようになってしまいました。

親ウィンドウの最大化・最小化によるサイズの変更に子ウィンドウを対応させるためにはどのように記述すればいいでしょうか?
どなたかよろしくお願いします。
添付ファイル
圧縮用.zip
(7.46 KiB) ダウンロード数: 130 回

wasawasa
記事: 94
登録日時: 11年前

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#2

投稿記事 by wasawasa » 11年前

コードを書くと長文になってしまうのでzip形式で添付したのですが、不評みたいなので気になる部分のコードだけ書いておきます。
質問の内容に変更はありません。
どなたかよろしくお願いします。

Base_WndProc.cpp

コード:

#include <windows.h>
#include <commctrl.h>

#include "MasterToolBer.h"
#include "Base.h"
#include "ModeZone.h"
#include "ControlID.h"
#include "StateBar.h"



//------------------------------------------------------------
//ウィンドウプロシージャ
//------------------------------------------------------------
//ソフト実行中の挙動を設定する
//------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	//終了命令時の終了確認用
	int id;
	//共通ツールバー格納構造体
	static HWND hToolbar;
	//ステータスバー用
	static HWND hStatus;
	//モード別描画領域用
	static HWND hModeZone;

	switch (msg) {
		case WM_CREATE:
			//ステータスバー
			hStatus = CreateStateBar(hWnd);
			//共通ツールバー
			hToolbar = CreateMasterTB(hWnd);
			//モード別描画領域
			hModeZone = CreateModeZone(hWnd);
			return 0;
		case WM_SIZE:
			//ステータスバー
			MoveStateBar(&hStatus);
			SendMessage(hStatus , msg , wp , lp);
			//共通ツールバー
			MoveMasterTB(&hToolbar);
			SendMessage(hToolbar , msg , wp , lp);
			//モード別描画領域
			MoveModeZone(&hModeZone);
			SendMessage(hModeZone , msg , wp , lp);
			return 0;
		case WM_SYSCOMMAND:
			//ステータスバー
			MoveStateBar(&hStatus);
			SendMessage(hStatus , msg , wp , lp);
			//共通ツールバー
			MoveMasterTB(&hToolbar);
			SendMessage(hToolbar , msg , wp , lp);
			//モード別描画領域
			MoveModeZone(&hModeZone);
			SendMessage(hModeZone , msg , wp , lp);
			return 0;
		//メニュー
		case WM_COMMAND:
			switch (LOWORD(wp)){
				case IDM_END:
					SendMessage(hWnd,WM_CLOSE,0,0);
					break;
				default:
					return(DefWindowProc(hWnd,msg,wp,lp));
			}
			break;
		//終了命令
		case WM_CLOSE:
			id = MessageBox(hWnd,
				TEXT("終了してもよろしいですか"),
				TEXT("確認"),
				MB_YESNO | MB_ICONQUESTION);
			if(id==IDYES){
				DestroyWindow(hWnd);
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return (DefWindowProc(hWnd, msg, wp, lp));
	}
	return 0;
}
StateBar.cpp

コード:

#include <windows.h>
#include <commctrl.h>

#include "ControlID.h"
#include "LayOut.h"
//ステータスバー生成
HWND CreateStateBar(HWND hWnd){
	HWND hStatus;
	RECT rc;

	HINSTANCE hInst = (HINSTANCE)GetWindowLongPtr(hWnd,GWL_HINSTANCE);//hWndのインスタンスハンドルをhInstに取得

	hStatus = CreateWindowEx(
		0,//拡張スタイル
		STATUSCLASSNAME,//ウィンドウクラス
		NULL,//タイトル
		WS_CHILD | SBARS_SIZEGRIP |//ウィンドウスタイル
		CCS_BOTTOM | WS_VISIBLE,//WS_VISIBLEを指定しないときは必ずShowWindow関数を呼ぶ
		0,//x座標
		0,//y座標
		0,//ウィンドウ幅
		0,//高さ
		hWnd,//親ウィンドウ
		(HMENU)ID_StateBar,//ID
		hInst,//インスタンスハンドル
		NULL);
	SendMessage(hStatus, SB_SIMPLE, 0, 0);
	SendMessage(hStatus,SB_SETTEXT, 0 | 0,
		(LPARAM)TEXT("test"));//ステータスバーテキスト
	//位置関係取得
	GetWindowRect(hStatus,&rc);
	LO_StateBar.x1 = rc.left;
	LO_StateBar.y1 = rc.top;
	LO_StateBar.x2 = rc.right;
	LO_StateBar.y2 = rc.bottom;
	LO_StateBar.width = LO_StateBar.x2 - LO_StateBar.x1;
	LO_StateBar.height = LO_StateBar.y2 - LO_StateBar.y1;
	return hStatus;
}
//ステータスバーサイズ取得
void MoveStateBar(HWND *hSB){
	RECT rc;
	//位置関係取得
	GetWindowRect(*hSB,&rc);
	LO_StateBar.x1 = rc.left;
	LO_StateBar.y1 = rc.top;
	LO_StateBar.x2 = rc.right;
	LO_StateBar.y2 = rc.bottom;
	LO_StateBar.width = LO_StateBar.x2 - LO_StateBar.x1;
	LO_StateBar.height = LO_StateBar.y2 - LO_StateBar.y1;
}
MasterToolBar.cpp

コード:

#include <windows.h>
#include <commctrl.h>

#include "ControlID.h"
#include "LayOut.h"

//共有ツールバー用ボタンデータ
TBBUTTON tbButton[] = {
	{ STD_FILENEW , 1 , TBSTATE_ENABLED , TBSTYLE_BUTTON , 0 , 0 , 0 } ,
	{ STD_FILEOPEN , 2 , TBSTATE_ENABLED , TBSTYLE_BUTTON , 0 , 0 , 0 } ,
	{ STD_FILESAVE , 3 , TBSTATE_ENABLED , TBSTYLE_BUTTON , 0 , 0 , 0 } ,
	{ 0 , 0 , TBSTATE_ENABLED , TBSTYLE_SEP , 0 , 0 , 0 } ,
	{ STD_COPY , 4 , TBSTATE_ENABLED , TBSTYLE_BUTTON , 0 , 0 , 0 } ,
	{ STD_CUT , 5 , TBSTATE_ENABLED , TBSTYLE_BUTTON , 0 , 0 , 0 } ,
	{ STD_DELETE , 6 , TBSTATE_ENABLED , TBSTYLE_BUTTON , 0 , 0 , 0 }
};
//共有ツールバー生成
HWND CreateMasterTB(HWND hWnd){
	HINSTANCE hInst;
	HWND hTool;
	TBADDBITMAP tb;
	RECT rc;
	int stdid;

	InitCommonControls();

	hInst = (HINSTANCE)GetWindowLongPtr(hWnd,GWL_HINSTANCE);//hWndのインスタンスハンドルをhInstに取得

	hTool = CreateToolbarEx(
		hWnd ,					//親ウィンドウ
		WS_CHILD | WS_VISIBLE ,	//ウィンドウスタイル
		ID_MasterToolBar ,		//コントロールID
		6 ,						//イメージの数
		hInst ,					//インスタンスハンドル
		IDB_STD_SMALL_COLOR ,	//ツールバーID
		tbButton ,				//ボタンデータ
		7 ,						//ボタンの数
		0 ,						//ボタンの幅
		0 ,						//ボタンの高さ
		0 ,						//イメージの幅
		0 ,						//イメージの高さ
		sizeof (TBBUTTON));

	//TBADDBITMAP構造体のメンバをセットして
	//TB_ADDBITMAPメッセージを送る
	tb.hInst = HINST_COMMCTRL;
	tb.nID = IDB_STD_SMALL_COLOR;
	stdid = SendMessage(hTool, TB_ADDBITMAP, 0, (LPARAM)&tb);
	//デフォ画像を使用するボタンのiBitmapを修正して
	//TB_ADDBUTTONSメッセージを送る
	tbButton[0].iBitmap += stdid;
	tbButton[1].iBitmap += stdid;
	tbButton[2].iBitmap += stdid;
	tbButton[4].iBitmap += stdid;
	tbButton[5].iBitmap += stdid;
	tbButton[6].iBitmap += stdid;

	//位置関係取得
	GetWindowRect(hTool,&rc);
	LO_MToolBar.x1 = rc.left;
	LO_MToolBar.y1 = rc.top;
	LO_MToolBar.x2 = rc.right;
	LO_MToolBar.y2 = rc.bottom;
	LO_MToolBar.width = LO_MToolBar.x2 - LO_MToolBar.x1;
	LO_MToolBar.height = LO_MToolBar.y2 - LO_MToolBar.y1;

	return hTool;
}
//共有ツールバーサイズ取得
void MoveMasterTB(HWND *hMTB){
	RECT rc;
	//位置関係取得
	GetWindowRect(*hMTB,&rc);
	LO_MToolBar.x1 = rc.left;
	LO_MToolBar.y1 = rc.top;
	LO_MToolBar.x2 = rc.right;
	LO_MToolBar.y2 = rc.bottom;
	LO_MToolBar.width = LO_MToolBar.x2 - LO_MToolBar.x1;
	LO_MToolBar.height = LO_MToolBar.y2 - LO_MToolBar.y1;
}
ModeZone.cpp

コード:

#include <windows.h>
#include <commctrl.h>

#include "ControlID.h"
#include "LayOut.h"
//モード別描画領域生成
HWND CreateModeZone(HWND hWnd){
	HINSTANCE hInst;
	HWND hModeZone;
	RECT rc;

	hInst = (HINSTANCE)GetWindowLongPtr(hWnd,GWL_HINSTANCE);//hWndのインスタンスハンドルをhInstに取得

	hModeZone = CreateWindowEx(
		WS_EX_WINDOWEDGE,
		TEXT("STATIC"),NULL,
		WS_CHILD | WS_VISIBLE,
		0,LO_MToolBar.height,
		LO_MToolBar.x2-LO_MToolBar.x1,LO_StateBar.y1-LO_MToolBar.y2,
		hWnd,
		(HMENU)ID_ModeZone,
		hInst,
		NULL);

	//位置関係取得
	GetWindowRect(hModeZone,&rc);
	LO_ModeZone.x1 = rc.left;
	LO_ModeZone.y1 = rc.top;
	LO_ModeZone.x2 = rc.right;
	LO_ModeZone.y2 = rc.bottom;
	LO_ModeZone.width = LO_ModeZone.x2 - LO_ModeZone.x1;
	LO_ModeZone.height = LO_ModeZone.y2 - LO_ModeZone.y1;

	return hModeZone;
}
//モード別描画領域サイズ変更
void MoveModeZone(HWND *hMZ){
	RECT rc;

	MoveWindow(*hMZ, 0, LO_MToolBar.height, LO_MToolBar.x2-LO_MToolBar.x1, LO_StateBar.y1-LO_MToolBar.y2, TRUE);

	//位置関係取得
	GetWindowRect(*hMZ,&rc);
	LO_ModeZone.x1 = rc.left;
	LO_ModeZone.y1 = rc.top;
	LO_ModeZone.x2 = rc.right;
	LO_ModeZone.y2 = rc.bottom;
	LO_ModeZone.width = LO_ModeZone.x2 - LO_ModeZone.x1;
	LO_ModeZone.height = LO_ModeZone.y2 - LO_ModeZone.y1;
}

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#3

投稿記事 by へにっくす » 11年前

たった一日で不評かどうかわかるわけないでしょ。
zipだけで十分だったのに。

zipを落として確認してみたけど、WM_SYSCOMMANDの場合だけで書いちゃったんだね。
WM_SYSCOMMAND
上記のリンクにあるように、システムコマンドすべてのメッセージがそこに行くので、動作がへんになるのも当然です。
wParamの判定をしてくださいね。
例えばウィンドウを最大化したときに動作させたいのであれば、

コード:

if((wParam & 0xFFF0) == 0xF030) {
    // 最大化したとき
}
という感じでさらに分岐が必要です。
もちろん処理しないケースがあるのなら、DefWindowProcに渡すのを忘れずに。
written by へにっくす

wasawasa
記事: 94
登録日時: 11年前

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#4

投稿記事 by wasawasa » 11年前

返信ありがとうございます。
気にしすぎてしまったみたいですみません。次から気を付けます。

wParamの判定が必要というご指摘を頂いたので、WM_SYSCOMMANDの場合の記述を下記のように書いて最大化・最小化時の動きを調べたところ、挙動がおかしいままでした。
PCの不調を引き起こす心配は無さそうだったのでウィンドウのボタンの動きを何回か試してみたところ、
最大化ボタンの挙動は1回目に押すと無反応で
              2回目に押すと添付画像"質問用.png"のようになり
   3回目以降は無反応、
最小化ボタンの挙動は1回目に押すと添付画像"質問用2.png"のようになり
    2回目に押すとクライアント領域下部にある無字のウィンドウがクライアント領域上部のウィンドウの下に移動し
             3回目以降は無反応、
終了ボタンの挙動は正常のまま
という動きをすることが分かりました。
スクロールによるサイズ変更も試しましたが、カーソルがウィンドウの外にしばらく出せなくなる、画面が一瞬固まるなどの症状がみられました。(こちらはPC全体への悪影響が怖いので複数回の試行は行っていません。)
また、WM_SYSCOMMANDの場合の記述をreturn 0;のみにして実行してみたところ、最大化・最小化・終了ボタンとスクロールによるサイズ変更が反応しなくなりました。ただし、こちらの場合は無反応以上の挙動をすることはありませんでした。

この結果を鑑みるに、case WM_SYSCOMMAND:の記述の時点で大なり小なり不調を引き起こしているように思えるのですが、msg判定条件の追加に対しての条件か何かがあるのでしょうか?

[case]
case WM_SYSCOMMAND:
//最小化時の処理
if((wp & 0xFFF0) == 0xF020){
//ステータスバー
MoveStateBar(&hStatus);
SendMessage(hStatus , msg , wp , lp);
//共通ツールバー
MoveMasterTB(&hToolbar);
SendMessage(hToolbar , msg , wp , lp);
//モード別描画領域
MoveModeZone(&hModeZone);
SendMessage(hModeZone , msg , wp , lp);
}
//最大化時の処理
else if((wp & 0xFFF0) == 0xF030){
//ステータスバー
MoveStateBar(&hStatus);
SendMessage(hStatus , msg , wp , lp);
//共通ツールバー
MoveMasterTB(&hToolbar);
SendMessage(hToolbar , msg , wp , lp);
//モード別描画領域
MoveModeZone(&hModeZone);
SendMessage(hModeZone , msg , wp , lp);
}
else{
DefWindowProc(hWnd,msg,wp,lp);
DefWindowProc(hStatus,msg,wp,lp);
DefWindowProc(hToolbar,msg,wp,lp);
DefWindowProc(hModeZone,msg,wp,lp);
}
return 0;
[/case]
添付ファイル
質問用2.png
実行→最小化
質問用2.png (55.53 KiB) 閲覧数: 5306 回
質問用.png
実行→最大化→最大化
質問用.png (45.77 KiB) 閲覧数: 5306 回

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#5

投稿記事 by へにっくす » 11年前

まず、コードは、[case]で囲むのではなく

コード:

で囲みます。間違えないでください。

まあ、それは置いといて、・・・
えっと・・・
[url=http://msdn.microsoft.com/ja-jp/library/cc410753.aspx]DefWindowProc[/url]の使い方が間違ってる。ちゃんとヘルプ見てますか?
ウィンドウプロシージャで渡されたhWndに対して何も処理しない場合に使うのですよ。
子供であるウィンドウhStatus、hToolbar、hModeZoneに対して使ってどうするのですか。挙動がおかしくなるのは当たり前です。
また、hWndに対してきたメッセージをそのままhStatus、hToolbar、hModeZoneを使ってSendMessageに渡してるのも意味がわかりません。

さらに、WndProcでDefWindowProcに渡さずにreturn 0;で返すと、そのメッセージは処理済みとみなされ、デフォルトの動きをしません。
[url=http://chokuto.ifdef.jp/urawaza/message/WM_SYSCOMMAND.html]WM_SYSCOMMAND[/url]のメッセージをreturn 0;でそのまま返せば当然、おっしゃったようにサイズ変更、閉じるなどが無反応になります。

要するに何も理解していないのですね。

[url=http://www.kumei.ne.jp/c_lang/]猫でもわかるプログラミング[/url]
のWindows SDKの1~4を順におってやって行くことをお勧めします。
written by へにっくす

Mana

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#6

投稿記事 by Mana » 11年前

ウィンドウのシステムメニューの項目が選択されたときやデスクトップからの通知で発生するのがWM_SYSCOMMAND。
WM_SYSCOMMANDを受け取った時点でその機能は実行されていない。
WM_SYSCOMMANDの戻り値を0にするのはその機能を横取りしてデフォルトの動作をキャンセルしたいとき。

ウィンドウのサイズが変更されたことはWM_SIZEで通知される。
WM_SIZEのWPARAMで発生理由が最大化や最小化だといったことが分かるのでそれを判断材料にすればいい。

子ウィンドウは子ウィンドウで適切にメッセージが流れる。
親ウィンドウのプロシージャが呼び出された内容をもって子ウィンドウに流し込むのは何が起きるか想像できない。

wasawasa
記事: 94
登録日時: 11年前

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#7

投稿記事 by wasawasa » 11年前

>>へにっくすさん
分かりました。

ちなみに本質問の件ですが、WM_SIZEの時の記述を下記のようにSendMessageを行ってから関数を起動させたらできるようになりました。ありがとうございました。

コード:

			if(wp==0 || wp==1 || wp==2 ){
				//メインウィンドウクライアント領域座標取得
				MasureMW(&hWnd);
				//ステータスバー
				SendMessage(hStatus , msg , wp , lp);
				MoveStateBar(&hStatus);
				
				//共通ツールバー
				SendMessage(hToolbar , msg , wp , lp);
				MoveMasterTB(&hToolbar);
				
				//モード別描画領域
				SendMessage(hModeZone , msg , wp , lp);
				MoveModeZone(&hModeZone);
				
			}

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#8

投稿記事 by へにっくす » 11年前

Manaさんの案を採用したのですね。それは良いことです。
ただ、何でhWndに対してきたメッセージをそのまま子ウィンドウに流すのかわかりません。そこだけ教えてもらえますか。
Mana さんが書きました:子ウィンドウは子ウィンドウで適切にメッセージが流れる。
親ウィンドウのプロシージャが呼び出された内容をもって子ウィンドウに流し込むのは何が起きるか想像できない。
この意味を理解してますか?
written by へにっくす

Mana

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#9

投稿記事 by Mana » 11年前

へにっくす さんが書きました:Manaさんの案を採用したのですね。それは良いことです。
見た目にだまされてはいけない。
No.7のWPARAM判定コードは意味がない。

Mana

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#10

投稿記事 by Mana » 11年前

ツールバーとステータスバーに親ウィンドウのWM_SIZEのパラメータを投げるのはリサイズのために必要なこと。
No.4では理解していると思えないが、理解したならば良い。

しかしスタティックコントロールは自らリサイズしない。
MoveModeZone関数では旧サイズを使ってMoveWindowしている。
多重発生するWM_SIZEに助けられ偶然動いている危ういコードと言えるのではないだろうか。

Mana

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#11

投稿記事 by Mana » 11年前

MoveModeZone関数で旧サイズを使っているというのは勘違いだった。すまない。
ツールバーとステータスバーのサイズを使ってそれらを除けたサイズを計算しているのだから正しかった。

お詫びに正しく動作する完全なコードを提供する。
基本的な問題だったので修正内容は単純である。
質問を深読みしてしまった。これについてもすまなかったと思う。

コード:

#include <windows.h>
#include <commctrl.h>

#include "MasterToolBer.h"
#include "Base.h"
#include "ModeZone.h"
#include "ControlID.h"
#include "StateBar.h"



//------------------------------------------------------------
//ウィンドウプロシージャ
//------------------------------------------------------------
//ソフト実行中の挙動を設定する
//------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
	//終了命令時の終了確認用
	int id;
	//共通ツールバー格納構造体
	static HWND hToolbar;
	//ステータスバー用
	static HWND hStatus;
	//モード別描画領域用
	static HWND hModeZone;

	switch (msg) {
		case WM_CREATE:
			//ステータスバー
			hStatus = CreateStateBar(hWnd);
			//共通ツールバー
			hToolbar = CreateMasterTB(hWnd);
			//モード別描画領域
			hModeZone = CreateModeZone(hWnd);
			return 0;
		case WM_SIZE:
			//ステータスバー
			SendMessage(hStatus , msg , wp , lp);
			MoveStateBar(&hStatus);
			//共通ツールバー
			SendMessage(hToolbar , msg , wp , lp);
			MoveMasterTB(&hToolbar);
			//モード別描画領域
			MoveModeZone(&hModeZone);
			return 0;
		//メニュー
		case WM_COMMAND:
			switch (LOWORD(wp)){
				case IDM_END:
					SendMessage(hWnd,WM_CLOSE,0,0);
					break;
				default:
					return(DefWindowProc(hWnd,msg,wp,lp));
			}
			break;
		//終了命令
		case WM_CLOSE:
			id = MessageBox(hWnd,
				TEXT("終了してもよろしいですか"),
				TEXT("確認"),
				MB_YESNO | MB_ICONQUESTION);
			if(id==IDYES){
				DestroyWindow(hWnd);
			}
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return (DefWindowProc(hWnd, msg, wp, lp));
	}
	return 0;
}

Mana

Re: 親ウィンドウの最大化・最小化に子ウィンドウを対応させたい

#12

投稿記事 by Mana » 11年前

連投すまない。
前投稿のコードはBase_WndProc.cppの内容である。

閉鎖

“C言語何でも質問掲示板” へ戻る