4

C++ でウィンドウを作成し、ウィンドウ サイズが設定したサイズと一致しない Rectangle を描画しようとしているときに、非常に厄介なことに気付きました。

たとえば、480x240 ウィンドウを設定し、GetWindowRect(hwnd, &rect) を取得して上から下、左から右に四角形を描画し、幅と高さを計算しようとすると、次のようになります。

rectangle_width = (rect.right - rect.left) / amountRectangleX;
rectangle_height = (rect.bottom - rect.top) / amountRectangleY;

amountRectangleX = 2 および Y = 2 の場合、4 つの長方形が描画されますが、幅と高さが「オフ」であるため、画面全体に表示されないか、その上にレンダリングされます。これが発生する唯一の方法は (私は他の多くの言語でこれを行ったので、それが機能することを知っています)、 Window Size = 480x240 を設定した場合、それを「描画」する領域にしたいということです。ウィンドウのサイズに境界線が含まれている場合、ウィンドウスタイルなどが異なる別のコンピューターでは異なるためです。そして、これを自分のコンピューターで手動で「変更」することはできません。

ウィンドウ サイズ = 480x240 に設定してスクリーンショットを撮ると、紛らわしいウィンドウ スペース = 452x232 が表示されます。ウィンドウ サイズ = 480x240 に設定しても問題ありませんが、GetWindowRect() を実行すると、480x240 ではなく 452x232 が取得されます。これは、描画するスペースが少ないため無効です。これは、なぜ私の Rectangles がウィンドウ空間を超えてレンダリングされるのかを説明し、私はそれを望んでいません。しかし、サイズ = 480x240 またはその他のものを設定できるようにしたいのですが、まだ境界線があります。

なぜこのように機能し、この問題の解決策はありますか? ウィンドウの解像度を設定できるようにしたいのは私だけではありません。使用するコンピューターに関係なく、設定したサイズは、描画できる描画領域です。

4

3 に答える 3

2

@Deukalion と同じように、目的のクライアント領域のサイズを誤って::CreateWindow()呼び出しに入れ、グリッドを描画しているときにピクセルが不足していることに気付きました。私は、アプリケーションのスクリーンショットのピクセル サイズを調査するという同じアプローチを取りました。ウィンドウの境界線とタイトル バーがクライアント領域からいくらかのスペースを奪っていることは理解できましたが、Windows 10 では、アプリケーション ウィンドウ全体でさえ要求されたサイズにならないのが不満です。

::CreateWindow()ハードコーディングされた幅と高さのピクセル数を差し引いて、より小さなクライアント領域を計算し、その周りにウィンドウの境界線とタイトル バーを構築していると思われます。そのハードコードされた数値は、Windows 10 の超薄型スターク ウィンドウ テーマでは正しくありません。ばかげています。で要求されたサイズの画面には何も::CreateWindow()ありません。

@PeterRuderman のアドバイスに従って、::AdjustWindowRect()呼び出しを使用しました。

RECT rect;
rect.left = rect.top = 0;
rect.right = clientWidth;
rect.bottom = clientHeight;
::AdjustWindowRect(&rect, wflags, false);
HWND hWindow = ::CreateWindow(wcName, title, wflags, 0, 0,
  rect.right - rect.left, rect.bottom - rect.top, 0, 0, hInstance, 0);
  • https://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspxに記載されているように、RECT 構造体はrightandbottomフィールドを意図した四角形の外側と見なします。
  • ::AdjustWindowRect()指定された原点座標 (0,0) をそのまま残して、呼び出しに直接入力できるようにするrightとよいでしょう。しかし驚いたことに、andフィールドは負になりました。bottom::CreateWindow()leftbottom
于 2015-12-24T17:06:08.137 に答える
1

問題を解決するのに十分な情報が提供されたとはまだ思いませんが、(基本的に) 必要なことを行う完全なプログラムを次に示します。自分のものと比較して、どこが間違っているかを確認できます。

#include <Windows.h>

LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uMsg ) {
    case WM_CLOSE:
        PostQuitMessage( 0 );
        break;

    case WM_PAINT:
        {
            RECT clientArea;
            GetClientRect( hwnd, &clientArea );

            PAINTSTRUCT ps;
            BeginPaint( hwnd, &ps );

            HBRUSH brush = (HBRUSH)GetStockObject( BLACK_BRUSH );

            RECT topLeft = clientArea;
            topLeft.right /= 2;
            topLeft.bottom /= 2;

            RECT bottomRight = clientArea;
            bottomRight.left = bottomRight.right / 2;
            bottomRight.top = bottomRight.bottom / 2;

            FillRect( ps.hdc, &topLeft, brush );
            FillRect( ps.hdc, &bottomRight, brush );

            EndPaint( hwnd, &ps );
        }

        return 0;
    }

    return DefWindowProc( hwnd, uMsg, wParam, lParam );
}

int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    // Error checking omitted for brevity.
    WNDCLASSEX wc = { 0 };

    wc.cbSize = sizeof( wc );
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = L"testclass";

    ATOM classAtom = RegisterClassEx( &wc );

    HWND window = CreateWindow( L"testclass", L"Test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 480, 240, NULL, NULL, hInstance, NULL );

    MSG msg;

    while( GetMessage( &msg, NULL, 0, 0 ) ) {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

編集

質問を読み直した後、AdjustWindowRect API を探しているだけだと思います。その場合、あなたの質問は次のようなものです: WinAPI: Create a window with a specified client area size . 今後の参考のために、「描画できる領域」をクライアント領域と呼びます。

于 2012-08-02T18:40:52.240 に答える