FAQ11-1

Q. 固定サイズのクライアントエリアを作るには

 ツールバー,メニュータイトルバーなどを含んだウィンドウで,固定サイズのクライアントエリア(例:640x400の描画エリアを持ったSDI Window)を作るためにはどうすればよいのでしょうか.
(角田 仁さんからの質問です)


A. AdjustWindowRectEx()を使う

AdjustWindowRectEx()を使う

 クライアント領域のサイズをもとに,ウィンドウのサイズも求めるには,Windows APIのAdjustWindowRect(),またはAdjustWindowRectEx()を使います.これらの関数は,ウィンドウハンドルは渡さずにウィンドウスタイルを引数にしています.
 AdjustWindowRect()とAdjustWindowRectEx()の違いは,拡張スタイルも考慮するかどうかの違いで,通常は拡張スタイルも考慮してAdjustWindowRectEx()を使ったほうがよいでしょう.AdjustWindowRectEx()の使い方をリスト11-1に示します.
 lprcにクライアント領域のRECT構造体のアドレスを指定してこの関数を呼ぶと,関数が成功すれば,同じRECT構造体にウィンドウのサイズが返ってきます.
 ウィンドウハンドルをもとに,クライアント領域固定サイズのウィンドウにサイズ変更するにはリスト11-2のようにします.

[リスト11-1] :

AdjustWindowRectEx( lprc, dwStyle, fMenu, dwExStyle );
	LPRECT lprc;      		クライアント領域の矩形
	DWORD dwStyle;   		ウィンドウスタイル
	BOOL fMenu;     			ウィンドウがメニューを持つかどうか
	DWORD dwExStyle;	拡張スタイル

[リスト11-2] :

void MyAdjustWindow( HWND hwnd, BOOL fMenu, int cx, int cy ) {

	RECT  rc;
	SetRectEmpty( &rc );

	rc.right = cx;
	rc.bottom = cy;

	AdjustWindowRectEx(&rc,GetWindowLong(hwnd,
		GWL_STYLE ),fMenu,GetWindowLong(hwnd,
		GWL_EXSTYLE)  );

	int cxNew = rc.right - rc.left;
	int cyNew = rc.bottom - rc.top;

	SetWindowPos(hwnd,NULL,0,0,cxNew,cyNew,
		SWP_NOZORDER | SWP_NOMOVE );
}

GetSystemMetrics()で計算する

 AdjustWindowRectEx()を使わなくても,ウィンドウの各パーツの大きさを計算して,自分でAdjustWindowRectEx()と同じことをすることもできます.
 ウィンドウの各パーツの大きさ求めるには,GetSystemMetrins()というAPIを使います.GetSystemMetrins()の使い方をリスト11-3に示します.

[リスト11-3] :

  int GetSystemMetrics( nIndex )
  int nIndex;

  nIndexに指定する値の例
    SM_CXBORDER		ウィンドウ枠の幅
    SM_CXFRAME		サイズ変更できるウィンドウ枠の幅
    SM_CXVSCROLL	垂直スクロールバーの(矢印の)幅
 GetSystemMetrics()に目的のパーツを指定して呼ぶと,返り値にその大きさが返ってきます.
 この各パーツの値と,クライアント領域の大きさを加算すればウィンドウのサイズを計算することができます.
 例えば,図11-1のようなウィンドウの場合,以下のようにして計算します.
 int cxClient = (クライアント領域の幅);
 int cyClient = (クライアント領域の高さ);
 int cx = cxClient
 +GetSystemMetrics(SM_CXFRAME )*2
 +GetSystemMetrics(SM_CXVSCROLL );
  int cy = cyClient
 +GetSystemMetrics( SM_SYFRAME )*2
 +GetSystemMetrics( SM_CYCAPTION )
 +GetSystemMetrics( SM_CYMENU );

[図11-1] :

ツールバーやステータスバー

 ツールバーやステータスバーがある場合は,求めたウィンドウのサイズにさらにツールバーの大きさなどを加算するだけでです.大きさがわからない場合は,無理矢理ウィンドウサイズを推測してもよいでしょう.
 例えば,図11-2のようにMFCのプログラムでツールバーとステータスバーがあって,この大きさがどう変化するかわからない場合があったとします.

[図11-2] :

 このとき,まず修正前にフレームウィンドウの大きさとビューウィンドウの大きさの差を求めておきます.
 この差は,クライアント領域以外の余った部分の大きさということになるので,この大きさに固定クライアント領域の大きさを加えれば,フレームウィンドウの大きさが求まります.

Windows95での誤差

 MFCを使ったプログラムの場合,AdjustWindowRectEx()やGetSystemMetrics()で計算した値を使っていると,Window95でサイズの誤差が出てしまいます.
 どういった誤差かというと,図11-3を見てください.Windows3.1ではビューウィンドウのクライアント領域とウィンドウの大きさは等しかったのですが,Windows95ではクライアント領域とウィンドウの大きさは等しくないのです.

[図11-3] :

 この問題は,AdjustWindowRectEx()をビュー用とフレーム用に2段階に分けて計算することで回避できます.
 例えば,ビューのクライアント領域(図11-4)から,フレームウィンドウの大きさを求めるには,
(1) AdjustWindowRectEx()で,ビューのクライアントの大きさからビューのウィンドウの大きさを計算する.
(2) ビューのウィンドウの大きさから,フレームのクライアントの大きさを計算する(この例の場合は等しい).
(3) AdjustWindowRectEx()で,フレームのクライアントの大きさからフレームのウィンドウの大きさを計算する.
というようにしなければなりません.
 Windows95が出る前に作ったプログラムは,こんなことはわからないので,ずれてしまうことになります.

[図11-4] :


Back to FAQ main page