4

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

例如,如果我设置 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,我希望它成为“DRAW”的区域。因为如果边框包含在窗口的大小中 - 在另一台具有不同窗口样式等的计算机上会有所不同。而且我不能只是为我的计算机手动“更改”它。

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

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

4

3 回答 3

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

}
于 2012-08-07T14:09:05.587 回答
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) 保持不变,那就太好了,这样rightbottom可以直接填充到::CreateWindow()调用中。但令我惊讶的是,leftandbottom字段变为负数。
于 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 回答