获取确切的窗口区域大小 - CreateWindow窗口大小不正确窗口大小

时间:2012-08-02 17:53:57

标签: c++ window gdi createwindow

在尝试使用C ++创建窗口并绘制窗口大小与我设置的大小不匹配的矩形时,我注意到一些非常烦人的事情。

例如,如果我设置480x240窗口并尝试通过获取GetWindowRect(hwnd,& rect)从上到下,从左到右绘制矩形并计算宽度和高度:

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

如果amountRectangleX = 2且Y = 2则绘制4个矩形,但宽度和高度为“off”,因此它不会填满整个屏幕或者渲染它。这种情况发生的唯一方法(我已经用很多其他语言完成了所以我知道它有效)是如果我设置Window Size = 480x240我希望它是“DRAW”的区域。因为如果窗口大小中包含边框 - 在具有不同窗口样式的另一台计算机上会有所不同。我不能只为我的电脑手动“改变”这个。

如果我设置窗口大小= 480x240并截取屏幕截图,我看到Window Space = 452x232令人困惑。如果我设置窗口大小= 480x240就可以了,但是当我GetWindowRect()时,我得到452x232而不是480x240然后无效,因为我有更少的空间来绘制。这可以解释为什么我的矩形渲染超出窗口空间而我不希望这样。但我仍然希望能够设置我的尺寸= 480x240或其他任何东西,但仍然有边框。

为什么它以这种方式工作,是否有解决此问题的方法? 我不能是唯一一个想要设置窗口分辨率的人,无论你使用什么计算机,你设置的那个尺寸都是你可以利用的绘图区域。

3 个答案:

答案 0 :(得分:2)

我使用这种方法现在可行:

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

}

答案 1 :(得分: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结构将rightbottom字段视为预期的矩形。
  • 如果::AdjustWindowRect()保留给定的原点坐标(0,0),那将会很好,这样rightbottom就可以直接填入{{1}调用。但令我惊讶的是,::CreateWindow()left字段变为否定。

答案 2 :(得分: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。为了将来参考,“您可以绘制的区域”称为客户区。