許せない心理テスト

突然ですが、DirectX9について質問させて頂きます。

ウィンドウモードとフルスクリーンモードを切り替える
プログラムを組んでいますが、なぜか、フルスクリーンモード
からウィンドウモードに復帰すると画面サイズが変化してしまいます。

以下がその問題となる関数です。


void SetWindowStyle( HWND hWnd, bool g_WindowMode )
{
    if( g_WindowMode )
    {
        SetWindowLong( hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE );
        MoveWindow( hWnd, 0, 0, 0, 0, false );
        SetClientSize( hWnd, WINDOW_WIDTH, WINDOW_HEIGHT );// 以下に記載
    }
    else
    {
        SetWindowLong( hWnd, GWL_STYLE, WS_POPUP | WS_VISIBLE );
        MoveWindow( hWnd, 0, 0, 800, 600, true );
    }
}



以下はウィンドウのサイズを再設定する関数です。


void SetClientSize( HWND hWnd, int width, int height )
{
    RECT wnd_Rect, clt_Rect;
    int WindowSize_Width, WindowSize_Height;

    GetWindowRect( hWnd, &wnd_Rect );
    GetClientRect( hWnd, &clt_Rect );

    // ウィンドウのサイズを求める
    WindowSize_Width = ( wnd_Rect.right - 1 ) - ( wnd_Rect.left - 1 );
    WindowSize_Height = ( wnd_Rect.bottom - 1 ) - ( wnd_Rect.top - 1 );

    // ウィンドウのサイズを変更
    MoveWindow(    hWnd,
            wnd_Rect.left,
            wnd_Rect.top,
            width + (WindowSize_Width-clt_Rect.right),
            height + (WindowSize_Height-clt_Rect.bottom),
            true
    );
}


SetClientSize関数はアプリ起動時に一度実行され、800x600に変更されます。
この時点では問題はありません。

しかし、フルスクリーンモード→ウィンドウモードと切り替えると、
800x576と値がおかしくなります。
結果的に800x600になる予定だったのですが…。

同じ関数を使用しているのに、なぜサイズが変化してしまうのでしょう?
どなたかこの問題を解決する方法をご存知ないでしょうか?

よろしくお願いします。

A 回答 (4件)

>クライアント領域のみをキャプチャ、サイズを測定しています。


キャプチャ画像からでは、デスクトップの解像度に
よっては縦横比が変わった場合、正しいウィンドウサイズの
値が取得できないと思います。
#縦長になったり、横長になったりします。

>初期状態がどうあれ、後に値が変化することは想定外ですので。
>試しに、ウィンドウモードを変更する直前にスクリーン座標を退避、
>復帰時に退避した座標を適用、といった動作も試しましたが、結果はまったく
>同じでした。
サイズを変更するAPIを呼び出している以上、設定した値が
おかしいのだとは思いますが、スクリーン座標を補完する事に
意味があるのでしょうか?変更するまえの位置に表示したい
などの場合以外では縦横のサイズの変化には、
あまり意味が無いような気がします。

>MoveWindow( hWnd, 0, 0, 0, 0, false );
>をコメントアウトしただけでも正しく表示されません。
原点に移動し、ウィンドウサイズを0,0に指定していますが、
実際にはウィンドウは0,0にならずにシステムメニューなどの
サイズで最小サイズとしてデスクトップ上に残るため、
(本当にそうなのかは微妙ですが、私の環境ではそうなりました。)
このサイズをGetWindowRect、GetClientRectで取得し
この時おそらく、クライアント領域の高さは0に成ると思うので
その状態で、タイトルやメニューのサイズを算出しているのでは??

もし、上記のコードで設定した値0,0,0,0が、
GetWindowRectで取得された場合は、
ウィンドウ全体のサイズが800x600となり
システムメニュー分の高さがクライアント領域から
引かれる可能性は無きにしも在らずですが、
本来であれば、メニューのサイズやタイトルのサイズは
GetSystemMetrics関数で取得するのが最も正確な値となると思うので、
そちらを使うというのも一つの手だとは思います。

ただ、ウィンドウサイズを調べる場合は、
きちんとAPIなどで取得した値を見たほうが良いと思います。
開発環境でのキャプチャ画像などから実測すると、
実行環境での誤差が出る可能性が高いです。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございます。

どうやら、
フルスクリーンから復帰(この時点でフレームは描画されていない)⇒
ウィンドウサイズを変更(この時点で、正しく動作していない)⇒
クライアント領域の上にフレームが描画される⇒
結果、タイトルバーの分だけサイズが小さくなる、というものの様です。

原因はよく分かりませんが、引数は関係ないことだけは確認できました。

お礼日時:2010/06/15 18:53

机上だとわかり難かったので試してみました。


わたしの環境では試したころ、提示されたコードでは、
ウィンドウサイズは特に問題なく動作しているようで、
808x627という値が毎回設定されていました。
以下の補足をお願いします。
#少し大きくなっていますが、
#タイトルバーなどを考慮したサイズにはなっているようです。

>800x576と値がおかしくなります。
この値はどの様に確認されたのでしょうか?
#わたしはデバッグウィンドウで確認しました。

また、この値は、Window領域のものでしょうか?
それとも、DirectXのデバイスに与えているサイズでしょうか?
DirectXにはスクリーンモードがありますので、
これを変更する場合には、デバイスの再作成が必要となりますが。。。

補足の内容からすると、
ウィンドウモード→フルスクリーンモード→ウィンドウモードの
時に値がおかしくなるということで良いでしょうか?

DirectXのサイズを変更と成ると少し話が違ってくるので。。。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございます。

私は、ウィンドウキャプチャアプリケーションを使用して、
クライアント領域のみをキャプチャ、サイズを測定しています。
そのため、通常は800x600になるように計算してありますので、数値の
間違いは無いと思います。

そして、当面の問題はこのウィンドウサイズの矛盾ですね。
初期状態がどうあれ、後に値が変化することは想定外ですので。

試しに、ウィンドウモードを変更する直前にスクリーン座標を退避、
復帰時に退避した座標を適用、といった動作も試しましたが、結果はまったく
同じでした。


また、SetWindowStyle関数内6行目の

MoveWindow( hWnd, 0, 0, 0, 0, false );

をコメントアウトしただけでも正しく表示されません。
SetClientSize関数内で同関数は実行されているのですが…。

気のせいか、メニューバーのサイズ分だけ、差し引かれているような気が…。
近々試してみる予定です(仮にそれで直ったところで、結局、原因は不明なままですが)。

度々ご迷惑をお掛けしますが、ご回答頂けると幸いです。

お礼日時:2010/06/02 02:41

No1です。



>ウィンドウサイズの変更を行っていませんので、
よく見たら、ウィンドウサイズは毎回変更されていますね。。。

ウィンドウモードの場合は、クライアント領域を800x600にするように
ウィンドウモードに変更する際に、タイトルやメニューの高さを
考慮すれば正しく、調整されると思います。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございます。
最初の投稿へのご返答ですが、ウィンドウのサイズが…は、
クライアントサイズが…が正しい表現でしたね。御幣がありました。

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

上記の定義も欠落していました。

ですが、タイトルバーの長さはSetClientSize関数で考慮されていると思うのですが…。
実際、アプリ起動時にこの関数を呼び出して、クライアントサイズは800x600となっていますので。

メニューバは最初から追加していないので、考慮する必要性はないと思うのですが…?

お礼日時:2010/05/31 17:46

起動時はフルスクリーンモードで


WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
ということでしょうか?

まず、基本的なところですが、
ウィンドウ領域とクライアント領域の違いを理解されていますでしょうか?
また、なぜウィンドウサイズの変更が必要なのかを理解されていますか?

ウィンドウ領域とは、そのウィンドウの全体の領域を指します(タイトル領域や
メニュー領域ステータスバー、サイズ変更バーやボーダの領域を含んだ領域)
クライアント領域とは上記の、タイトルやボーダーを含まないサイズとなります。

通常、ポップアップウィンドウはタイトルバーなどが存在しないため、
ウィンドウ領域とクライアント領域は基本的に等しくなります。
オーバーラップウィンドウは、タイトルバーやボーダーなどが、
加味されるため、ウィンドウ領域とクライアント領域が等しくなりません。

この為、「ウィンドウスタイル」を切り替える場合は、
ウィンドウサイズの変更が必要に成るわけです。
#モードだけ変更するならば、そもそもウィンドウサイズを
#変更する必要はありません。
#(まぁ、ウィンドウ自体にはモードという概念はありませんが。)

提示されたプログラムでは、ウィンドウモードに変更された時しか
ウィンドウサイズの変更を行っていませんので、
フルスクリーンからウィンドウモードに切り替えると、
タイトル分ずれてウィンドウサイズが変更され、
ウィンドウモードからフルスクリーンに切り替えると、
変更されたウィンドサイズがそのまま使用されることになります。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございます。

ウィンドウのフレームのサイズは考慮してリサイズしています(多分)。

ややこしいソースになってしまいましたが、ご指摘お願いします。

お礼日時:2010/06/15 18:56

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報