ウィンドウスタイルの変更がうまくいきません。 – プログラミング – Home

ウィンドウスタイルの変更がうまくいきま...
 
通知
すべてクリア

[解決済] ウィンドウスタイルの変更がうまくいきません。


まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

お世話になります。
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です。

よろしくお願いします。


引用未解決
トピックタグ
Ban
 Ban
(@ban)
Prominent Member
結合: 5年前
投稿: 776
 

# ちゃんと見てなくてごめんなさい。

とりあえず反映されないだけならModifyStyleとか。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

> 「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


返信引用
とも
 とも
(@とも)
ゲスト
結合: 23年前
投稿: 65
 

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 );
}

これでどう?


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

皆さん、ありがとうございます。
問題点1については、とりあえず
ダイアログのBorderプロパティを
「ダイアログ枠」から「細枠」にすればうまくいくので、
それでやってみようと思います。
「ダイアログ枠」と「細枠」の違いが
未だに理解できてないですけど…。

問題点2については、ModeWindowをなくし、
代わりにSetWindowPosにしたら、一応、
うまくいくようになりました。
(ShowWindowでも同様になりました)

ただ、まだまだ問題がありまして…。
ウィンドウサイズを切り替えても、
画面上、何の変化も現れないんです。
その上に別アプリを重ねてどけると、
はじめて変化が確認できる、といった感じで…。

特に、ウィンドウスタイルを「タイトルバーなし」に切り替えた場合は、
ダイアログのクライアント領域の周囲に、
重ねた別アプリの表示内容が残ってしまいます。

SetWindowLong実行後にModeWindowを実行すれば
この現象は防げるのですが、
そうすると今度は問題点2が再発してしまう…
といった感じです。

この辺の問題は、ともさんのソースだと、比較的うまくいってます。
ModeWindow初回実行時に限り、すぐに変化が現れ、
その後も、標準ウィンドウに戻すことができました。
ただしそれ以降は、別アプリを重ねてどけないと
変化が確認できないです…。

ちなみに参考書は、SoftBankCreate社の
「Windowsゲームプログラミング」です。
この本では、確かに「SetWindowLongを行った後、
ShowWindowを行え」と書かれています。
昨日はほんと、「本の通りにやってるはずなのになんでうまくいかないんじゃ~」と、
なかばヤケになりかけてました…。
ModifyStyleとかSetWindowPosとか、もう少し自分の方も調べてみます。
皆さん、ありがとうございました。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

すいません、訂正です。
> ウィンドウサイズを切り替えても、
→ウィンドウスタイルを切り替えても


返信引用
wclrp ( 'o')
 wclrp ( 'o')
(@wclrp ( 'o'))
ゲスト
結合: 18年前
投稿: 287
 

もともとウィンドウスタイルを後から変更するようには設計されていないからね。
SetWindowLongなどでウィンドウスタイル変更しても、それを知らせる通知メッセージ
WM_~がない。そもそもSetWindowLongってウィンドウスタイル変更用APIじゃないし。

だから代わりにModeWindowやSetWindowPosでウィンドウを再描画させている。
でも、ウィンドウを再描画するときに、そのウィンドウプロシージャが新しいウィンドウ
スタイルを再確認して完全に動作が変わるように実装されていないと意味がない。

実際に各種(ダイアログやコントロール)でいくつかのウィンドウスタイルが変更できな
い報告があるし、経験もある。
たとえば、ダイアログで最初にサイズ変更可能な枠にしていなくて、後からサイズ変更可
能な枠に変えても、マウス操作でウィンドウサイズを変更してくれないっていう話を掲示
板でたまに見かける。これに関して俺は動作確認したことないけど。

ということで、何がいいたいかと言うと、ウィンドウの種類と、最初のウィンドウスタイ
ルと、後のウィンドウスタイルの種類によっては、出来ないこともあるよ。
今回のケースが可能か不可能かまでは俺にはわからないけど。


返信引用
wclrp ( 'o')
 wclrp ( 'o')
(@wclrp ( 'o'))
ゲスト
結合: 18年前
投稿: 287
 

よく読んでみると、
> ダイアログのクライアント領域の周囲に、
> 重ねた別アプリの表示内容が残ってしまいます。
外枠の再描画ができていないだけか。
じゃあたぶんSWP_DRAWFRAMEで上手く行くと思う。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

「SetWindowLong」 MSDNヘルプ解説より、

> ウィンドウデータの中には、キャッシュされており、
> SetWindowLong 関数を使って変更しても SetWindowPos 関数を呼び出すまでは
> 有効にならないものもあります。特に、フレームスタイルを変更した場合は、
> SWP_FRAMECHANGED フラグをセットして
> SetWindowPos 関数を呼び出すさなければ、キャッシュが正しく更新されません。

>SWP_FRAMECHANGED フラグをセットして
セットしてありますか?


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

シャノンさんが先に「2007/04/11(水) 09:56:57」で言っていますね。
しっかりとヘルプ読んだほうがいいです。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

まにさん、
あまり.netも含めてVisual Cに付属のMSDN LibraryCDを活用してないような
気がします。
INETで検索する前に、「付属のMSDN LibraryCD」で検索してみませんか?
検索時間も短くて済むと思います。
.net 2005はMFCのヘルプはないとか?...
未だインストールしてないので.....


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

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のヘルプには、
苦手意識を抱いてしまってます。
内容が分かりづらかったり英語だったりするので…。
せっかく答えを示していただいたのに、
よく読んでなくてすみません。
本当に、ありがとうございました。


返信引用
RAPT
 RAPT
(@RAPT)
ゲスト
結合: 22年前
投稿: 310
 

正直、アルファベットに抵抗を抱いているようでは、情報収集もままならないでしょう。
Web 版の MSDN なら日本語訳版もありますし、英語といってもさほど難しくないので
日本語訳版と見比べているうちに、ある程度読めるようになるはずです。
(構成が一緒なので、慣れれば必要な情報がどの辺にあるか分かるようになります。)

MSDN はクセがあるので、最初は大変かとは思いますが、早目に慣れた方がいいと思います。


返信引用
まに
 まに
(@まに)
ゲスト
結合: 18年前
投稿: 78
Topic starter  

うーーーん、やはり、
苦手言ってるようじゃ駄目なんですね。
なんとか読めるようにしたいと思います…。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました