Win7で VC++2012の MFC(シングルドキュメント)を使用している者です。
クライアント領域の大きさを指定しようと思い、PreCreateWindowの中身を
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタ
イルを
// 修正してください。
//変更点 ここから
cs.style = WS_MINIMIZEBOX |WS_POPUPWINDOW |WS_CAPTION
;
// 指定したクライアントサイズ
int cxClient =800;
int cyClient = 600;
int cx = cxClient
+GetSystemMetrics(SM_CXEDGE )*2
+GetSystemMetrics(SM_CXBORDER )*2;
int cy = cyClient
+GetSystemMetrics( SM_CYEDGE )*2
+GetSystemMetrics(SM_CYBORDER )*2
+GetSystemMetrics( SM_CYCAPTION )
+GetSystemMetrics( SM_CYMENU );
cs.cx=cx;
cs.cy=cy;
//変更点 ここまで
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
}
としたのですが、実測してみると、どうも縦横共に12ピクセルほど足りません。
どうすればクライアント領域を800×600丁度にできますでしょうか。
ナニが足りないのか…は未確認ですが……
>クライアント領域の大きさを指定しようと思い
であれば、AdjustWindowRect()、またはAdjustWindowRectEx()が使えませんか?
CREATESTRUCT構造体にstyleとdwExStyleもあるようですから、算出する際に利用できるかと。
# 算出前にRECT構造体にはよろしく値を設定する必要がありますけどね。
ご返答、ありがとうございます。
言葉足らずで申し訳ありません。
実行結果のウインドウのクライアント領域が、指定よりも縦横共に12ピクセル足りない、
という意味です。
また、AdjustWindowRectEx及びAdjustWindowRectEを、PreCreateWindow内に
RECT rect={0,0,800,600};
AdjustWindowRectEx(&rect,cs.style,true,cs.dwExStyle);
の様に置いて実行しましたが、指定した大きさのクライアント領域を持つウインドウには
なりませんでした。
フレーム(NC)を持つウインドウの、クライアント領域の大きさを
指定通りにしようとする試みは、失敗するか、将来破綻します。
原理的にクライアント領域は、フレームのサイズから、
フレームのスタイルや、クライアントのスタイルで使用されるピクセル数の
減算で算定される、いわば「残りの領域」であるからですね。
これらの中には動的に変化するスクロールバーなども含まれてしまいます。
また、これらのピクセル数は、適用されるテーマや、デフォルトのフォント、
ユーザー補助の適用、最近はモニタの高解像度化の影響で、デフォルトの
倍率が設定される、などによっても動的に変更されますので、
これらの全ての影響を事前に検知して算定に組み入れることは不可能です。
以上の通り不毛な作業となるばかりか、その仕様自体が瑕疵あつかいされると
考えられますので、その仕様の検討は中止すべきだと思います。
Spy++でフレームの大きさと、フレームのクライアント領域の大きさを比較してみてくだ
さい(Viewのウィンドウでは無く)。
ついでに、スタイル指定の結果も見てください。
(ひょっとしたら、SM_CXFIXEDFRAME,SM_CYFIXEDFRAMEかもしれません)
ゲームを作る場合など、クライアント領域のサイズを指定する場面は稀にありますね。
AdjustWindowRectExは実行後、クライアント領域の左上の原点を0として、
そこからウィンドウの左上・右下までの差分がRECTの中に入ります。
(フレームやメニューがあるとleft及びtopはマイナス値になる)
よって、ウインドウ全体の大きさは
RECT rect={0,0,800,600};
AdjustWindowRectEx(&rect,cs.style,true,cs.dwExStyle);
cs.cx=abs(rect.left)+rect.right;
cs.cy=abs(rect.top)+rect.bottom;
でOKなはずです。
多くのご意見、ありがとうございます。
teaさんのコードを試しましたが、クライアント領域が指定に対し縦横3ピクセル足りませ
んでした。
ほかにも、色々試しましたが、上手くいかず、仲澤@失業者さんのおっしゃるとおり、仕
様の検討を中止することを考えております。
大変失礼しました。こちらでも確認してみましたが、
確かにうまくいかないですね…。
どうやらView側のWS_EX_CLIENTEDGEがズレの原因のようで、View側から取り除て、
代わりにウィンドウ幅を算出するFrame側に付加することでうまくいきました。
ドッキングツールバーとステータスバーが無いことが条件になりますが、
念のため下記にコードを示しておきます。
MainFrm.cppのCMainFrame::PreCreateWindow内にて、
cs.dwExStyle |= WS_EX_CLIENTEDGE; // WS_EX_CLIENTEDGEを追加
RECT rect={0,0,800,600};
AdjustWindowRectEx(&rect,cs.style,true,cs.dwExStyle);
cs.cx=abs(rect.left)+rect.right;
cs.cy=abs(rect.top)+rect.bottom;
XXXView.cppのXXXView::PreCreateWindow内にて、元のreturn行をコメントアウトして
if (!CView::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE; // WS_EX_CLIENTEDGEを取り除く
return TRUE;
これでクライアント領域のサイズ指定はうまくいくと思いますが、
ツールバーやステータスバーが必要な場合はこの方法ではうまくいきません。
teaさん
再びのご返答、ありがとうございます。
MainFrameのPreCreateWindowにて
cs.style &= ~WS_MAXIMIZEBOX ;
cs.style &= ~WS_THICKFRAME;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
RECT rect={0,0,800,600};
AdjustWindowRectEx(&rect,cs.style,true,cs.dwExStyle);
cs.cx=abs(rect.left)+rect.right;
cs.cy=abs(rect.top)+rect.bottom;
とし、ViewのPreCreateWindowにて
if (!CView::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE; // WS_EX_CLIENTEDGEを取り除く
return TRUE;
としたところ、800×600のクライアント領域を持つウインドウができました。
他の方々からも、多くのご助言に感謝いたします。