2010年3月13日土曜日

クライアント領域を指定サイズに


  SetWindowPosでウィンドウのサイズを変更できるが、
クライアント領域を指定サイズにしたい場合は、フレーム部分を計算しなければならない。
各フレーム部分のサイズはGetSystemMetricsで取得できるので、

LONG winWidth = clientWidth +
  GetSystemMetrics(SM_CXEDGE) +
  GetSystemMetrics(SM_CXBORDER) +
  GetSystemMetrics(SM_CXDLGFRAME);
LONG winHeight = clientHeight +
  GetSystemMetrics(SM_CYEDGE) +
  GetSystemMetrics(SM_CYBORDER) +
  GetSystemMetrics(SM_CYDLGFRAME) +
  GetSystemMetrics(SM_CYCAPTION);

 と、以前は計算していた。どこだかで見かけてそのまま使わせていただいた。

今回新たにメニューバーをつけたのでメニューバーのサイズを計算に入れて

LONG winWidth = clientWidth +
  GetSystemMetrics(SM_CXEDGE) +
  GetSystemMetrics(SM_CXBORDER) +
  GetSystemMetrics(SM_CXDLGFRAME);
LONG winHeight = clientHeight +
  GetSystemMetrics(SM_CYEDGE) +
  GetSystemMetrics(SM_CYBORDER) +
  GetSystemMetrics(SM_CYDLGFRAME) +
  GetSystemMetrics(SM_CYCAPTION) +
  GetSystemMetrics(SM_CYMENU);  //< 加えた

 と、やったらいけるよね! と楽観視していたら、
最初の画像のようにウィンドウが小さいとメニューバーが2行になってしまってさあ大変。
 
 ちょろっと調べたところ、メニューが2行かどうか調べるよりいい方法があるようなので
そちらを採用して実行したところうまく動いた。

 処理は簡単で、
・とりあえず指定するクライアントのサイズでウィンドウサイズを変更、
・その状態でクライアント領域のサイズを取得して、
  ウィンドウサイズ-クライアントサイズでフレームのサイズを計算。
・クライアントサイズ+フレームサイズで ウィンドウサイズを設定
の流れ。


// 計算するためにとりあえず一回設定
SetWindowPos( hWnd, HWND_TOP, 0, 0, clientWidth, clientHeight, SWP_NOMOVE );
 
// 設定サイズと実際のサイズの誤差から正しいサイズを計算
RECT rect;
GetClientRect( hWnd, &rect );
const int frameWidth = clientWidth - rect.right;
const int frameHeight = clientHeight - rect.bottom;
const int winWidth = clientWidth + frameWidth;
const int winHeight = clientHeight + frameHeight;
 
// 設定
SetWindowPos( hWnd, HWND_TOP,
  0, 0, winWidth, winHeight, SWP_SHOWWINDOW | SWP_NOMOVE );


 いったん指定サイズに変更することでメニューが1行か2行かを決定するのがミソか。
最初はGetWindowRectとGetClientRectでフレームサイズを計算してたが、もちろんうまく行かない。
もっと正確に計算するのであれば、横幅だけはGetSystemMetricsでちまちまと計算するほうがいいかもしれない。
メニューが2行になっても長くなるのは縦方向だけなので、横幅に関しては差を取得するまでもないのと、
フレーム分を足して設定したときに、横幅が増えてメニューが1行になる可能性がある。

0 件のコメント: