Get exact window region size - CreateWindow window size isn't correct size of window

StackOverflow https://stackoverflow.com/questions/11783086

  •  24-06-2021
  •  | 
  •  

سؤال

I've noticed something very annoying while trying to create a window in C++ and draw Rectangles that the window size doesn't match the size I set.

For example, If I set the 480x240 window and try to Draw rectangles from top to bottom, left to right by getting GetWindowRect(hwnd, &rect) and calculate the width and height:

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

if amountRectangleX = 2 and Y = 2 it draw 4 rectangles, but the width and height is "off" so it doesn't fill up the whole screen or it renders over it. The only way this can happen (I've done this in alot of other languages so I know it works) is that if I set Window Size = 480x240 I want that to be the area to "DRAW" on. Because if borders are included in the size of the window - that would be different on another computer with different Window Style and such. ANd I can't just "alter" this manually for my computer.

If I set window size = 480x240 and take a screenshot I see that the Window Space = 452x232 which is confusing. It would be OK if I set window size = 480x240 but when I GetWindowRect() I get 452x232 and not 480x240 which then is invalid because I have less space to draw on. This would explain why my Rectangles render beyond the window space and I do NOT want that. But I still want to be able to set my size = 480x240 or anything else but still have borders.

Why does it work this way and is there a solution to this problem? I can't be the only one that want to be able to set the resolution of a window and no matter what computer you use, that size you set IS the DRAW AREA that you can draw upon.

هل كانت مفيدة؟

المحلول

I use this method and now it works:

if ( IsWindow( hwnd ) )
{

DWORD dwStyle = GetWindowLongPtr( hwnd, GWL_STYLE ) ;
DWORD dwExStyle = GetWindowLongPtr( hwnd, GWL_EXSTYLE ) ;
HMENU menu = GetMenu( hwnd ) ;

RECT rc = { 0, 0, width, height } ;

AdjustWindowRectEx( &rc, dwStyle, menu ? TRUE : FALSE, dwExStyle );

SetWindowPos( hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_NOMOVE ) ;

}

نصائح أخرى

Just like @Deukalion, I inadvertently put the desired client area size into the ::CreateWindow() call, and while drawing a grid, I found myself short of pixels. I took the same approach of investigating the pixel size of a screenshot of my application. I could understand that the window's borders and title bar take away some room from the client area - but the frustrating thing is that under Windows 10, not even the total application window has the requested size!

I suspect that ::CreateWindow() calculates a smaller client area by subtracting a hardcoded amount of pixels in width and height, and then builds the window border and title bar around that. That hardcoded number is no longer correct with the ultra-thin stark window theme of Windows 10. It's ridiculous - there's really nothing on the screen of the size that was requested in ::CreateWindow() !

I followed the advice of @PeterRuderman to use the ::AdjustWindowRect() call :

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);
  • As stated on https://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx the RECT struct considers the right and bottom fields as outside the intended rectangle.
  • It would have been nice if ::AdjustWindowRect() would have left the given origin coordinates (0,0) intact, so that right and bottom could be directly filled into the ::CreateWindow() call. But to my surprise, the left and bottom fields turned negative.

I still don't think you've provided enough info to solve your problem, but here's a complete program that does (basically) what you want. You can compare it to your own to see where you're going wrong.

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

Edit

After re-reading your question, I think you're just looking for the AdjustWindowRect API. In which case, your question is a duplicate of this one: WinAPI: Create a window with a specified client area size. For future reference, the "area you can drawn on" is called the client area.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top