お世話になります。
VC++2005(MFC)のダイアログベースのプログラムで、
ボタンを押すたびにウィンドウスタイルを、
①タイトルバーやダイアログ枠がない、クライアント領域のみのウィンドウスタイル
②タイトルバーや最小化ボタンがある、一般的なウィンドウスタイル
を交互に切り替えたいのですが、うまくいかずに苦戦しています。
以下、ソースコードと出力結果です。
===== ソースコード =====
void CTest16Dlg::OnBnClickedOk()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
WinStyleChange();
//OnOK();
}
// ウィンドウスタイル切替
void CTest16Dlg::WinStyleChange(void)
{
static bool Flg;
LONG ret,prm;
Flg = !Flg;
if (Flg) prm = WS_POPUP | WS_VISIBLE;
else prm = WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX
| WS_VISIBLE;
ret = SetWindowLong(this->m_hWnd, GWL_STYLE, prm);
MoveWindow(50,50,800,400);
//ShowWindow(SW_SHOW);
TRACE(=== Flg=%d ===\n, Flg);
TRACE(prm=%08X\n, prm);
TRACE(ret=%08X\n, ret);
}
===== 出力結果 =====
=== Flg=1 ===
prm=90000000
ret=94CA00C4
=== Flg=0 ===
prm=10CA0000
ret=94000000
問題点1
この関数(WinStyleChange)を一度実行すると、タイトルバーは表示されなくなるのです
が、
ダイアログの周囲の枠が表示されたままです。
この枠も非表示にさせたいのですが方法が分かりません。
ダイアログのBorderプロパティを「ダイアログ枠」から「細枠」に変更すれば一応うまく
いくのですが、
プログラム起動時にはこのプロパティをどちらに設定しても外見上変化がないため、
この両者の違いが分からず、果たして正しい方法かどうかが分かりません。
問題点2
この関数(WinStyleChange)を2回実行しても、ウィンドウスタイルが変化しません。
最大化ボタンが無効のタイトルバーが表示されるハズだと思うのですが…。
補足ですが、本によると
「SetWindowLongを行った後、ShowWindowを行え」
と書かれています。
しかし実行してみた限りではShowWindowを行っても画面上変化せず、
かわりにMoveWindowを実行しないとダメみたいです。
もっとも、問題点2は、どちらの場合でも解決しないのですが…。
その本はVC++2005専用の本ではないので、
その辺の違いなのかも知れません。
かれこれ6時間ぐらい苦戦してるので…。
問題な箇所がありましたら、ご指摘いただければありがたいです。
あと、環境はWinXP Homeです。
よろしくお願いします。
# ちゃんと見てなくてごめんなさい。
とりあえず反映されないだけならModifyStyleとか。
> 「SetWindowLongを行った後、ShowWindowを行え」
ShowWindow?
SetWindowPos じゃねぇの?
> ウィンドウデータの中には、キャッシュされており、SetWindowLong 関数を使って
> 変更しても SetWindowPos 関数を呼び出すまでは有効にならないものもあります。
> 特に、フレームスタイルを変更した場合は、SWP_FRAMECHANGED フラグをセットして
> SetWindowPos 関数を呼び出すさなければ、キャッシュが正しく更新されません。
http://msdn.microsoft.com/library/ja/default.asp?
url=/library/ja/jpwinui/html/_win32_setwindowlong.asp
void CTest16Dlg::WinStyleChange(void)
{
DWORD style = this->GetStyle();
if( style & WS_CAPTION )
this->ModifyStyle(
WS_THICKFRAME | WS_CAPTION | WS_MINIMIZEBOX,
NULL,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER );
else
this->ModifyStyle(
NULL,
WS_MINIMIZEBOX | WS_CAPTION | WS_THICKFRAME,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_DRAWFRAME );
}
これでどう?
皆さん、ありがとうございます。
問題点1については、とりあえず
ダイアログのBorderプロパティを
「ダイアログ枠」から「細枠」にすればうまくいくので、
それでやってみようと思います。
「ダイアログ枠」と「細枠」の違いが
未だに理解できてないですけど…。
問題点2については、ModeWindowをなくし、
代わりにSetWindowPosにしたら、一応、
うまくいくようになりました。
(ShowWindowでも同様になりました)
ただ、まだまだ問題がありまして…。
ウィンドウサイズを切り替えても、
画面上、何の変化も現れないんです。
その上に別アプリを重ねてどけると、
はじめて変化が確認できる、といった感じで…。
特に、ウィンドウスタイルを「タイトルバーなし」に切り替えた場合は、
ダイアログのクライアント領域の周囲に、
重ねた別アプリの表示内容が残ってしまいます。
SetWindowLong実行後にModeWindowを実行すれば
この現象は防げるのですが、
そうすると今度は問題点2が再発してしまう…
といった感じです。
この辺の問題は、ともさんのソースだと、比較的うまくいってます。
ModeWindow初回実行時に限り、すぐに変化が現れ、
その後も、標準ウィンドウに戻すことができました。
ただしそれ以降は、別アプリを重ねてどけないと
変化が確認できないです…。
ちなみに参考書は、SoftBankCreate社の
「Windowsゲームプログラミング」です。
この本では、確かに「SetWindowLongを行った後、
ShowWindowを行え」と書かれています。
昨日はほんと、「本の通りにやってるはずなのになんでうまくいかないんじゃ~」と、
なかばヤケになりかけてました…。
ModifyStyleとかSetWindowPosとか、もう少し自分の方も調べてみます。
皆さん、ありがとうございました。
すいません、訂正です。
> ウィンドウサイズを切り替えても、
→ウィンドウスタイルを切り替えても
もともとウィンドウスタイルを後から変更するようには設計されていないからね。
SetWindowLongなどでウィンドウスタイル変更しても、それを知らせる通知メッセージ
WM_~がない。そもそもSetWindowLongってウィンドウスタイル変更用APIじゃないし。
だから代わりにModeWindowやSetWindowPosでウィンドウを再描画させている。
でも、ウィンドウを再描画するときに、そのウィンドウプロシージャが新しいウィンドウ
スタイルを再確認して完全に動作が変わるように実装されていないと意味がない。
実際に各種(ダイアログやコントロール)でいくつかのウィンドウスタイルが変更できな
い報告があるし、経験もある。
たとえば、ダイアログで最初にサイズ変更可能な枠にしていなくて、後からサイズ変更可
能な枠に変えても、マウス操作でウィンドウサイズを変更してくれないっていう話を掲示
板でたまに見かける。これに関して俺は動作確認したことないけど。
ということで、何がいいたいかと言うと、ウィンドウの種類と、最初のウィンドウスタイ
ルと、後のウィンドウスタイルの種類によっては、出来ないこともあるよ。
今回のケースが可能か不可能かまでは俺にはわからないけど。
よく読んでみると、
> ダイアログのクライアント領域の周囲に、
> 重ねた別アプリの表示内容が残ってしまいます。
外枠の再描画ができていないだけか。
じゃあたぶんSWP_DRAWFRAMEで上手く行くと思う。
「SetWindowLong」 MSDNヘルプ解説より、
> ウィンドウデータの中には、キャッシュされており、
> SetWindowLong 関数を使って変更しても SetWindowPos 関数を呼び出すまでは
> 有効にならないものもあります。特に、フレームスタイルを変更した場合は、
> SWP_FRAMECHANGED フラグをセットして
> SetWindowPos 関数を呼び出すさなければ、キャッシュが正しく更新されません。
>SWP_FRAMECHANGED フラグをセットして
セットしてありますか?
シャノンさんが先に「2007/04/11(水) 09:56:57」で言っていますね。
しっかりとヘルプ読んだほうがいいです。
まにさん、
あまり.netも含めてVisual Cに付属のMSDN LibraryCDを活用してないような
気がします。
INETで検索する前に、「付属のMSDN LibraryCD」で検索してみませんか?
検索時間も短くて済むと思います。
.net 2005はMFCのヘルプはないとか?...
未だインストールしてないので.....
SetWindowPosにSWP_FRAMECHANGEDを追加したらうまくできました。
以下、うまくいったソースコードです。
// ウィンドウスタイル切替
void CTest16Dlg::WinStyleChange(void)
{
static bool Flg;
LONG prm;
Flg = !Flg;
if (Flg) prm = WS_POPUP | WS_VISIBLE;
else prm = WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^
WS_MAXIMIZEBOX | WS_VISIBLE;
SetWindowLong(this->m_hWnd, GWL_STYLE, prm);
this->SetWindowPos
(&wndTop,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_FRAMECHANGED);
}
ご指摘のように、正直、MSDNのヘルプには、
苦手意識を抱いてしまってます。
内容が分かりづらかったり英語だったりするので…。
せっかく答えを示していただいたのに、
よく読んでなくてすみません。
本当に、ありがとうございました。
正直、アルファベットに抵抗を抱いているようでは、情報収集もままならないでしょう。
Web 版の MSDN なら日本語訳版もありますし、英語といってもさほど難しくないので
日本語訳版と見比べているうちに、ある程度読めるようになるはずです。
(構成が一緒なので、慣れれば必要な情報がどの辺にあるか分かるようになります。)
MSDN はクセがあるので、最初は大変かとは思いますが、早目に慣れた方がいいと思います。
うーーーん、やはり、
苦手言ってるようじゃ駄目なんですね。
なんとか読めるようにしたいと思います…。