【问题标题】:Get exact window region size - CreateWindow window size isn't correct size of window获取确切的窗口区域大小 - CreateWindow 窗口大小不是正确的窗口大小
【发布时间】:2012-07-31 18:09:06
【问题描述】:

在尝试用 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 或其他任何东西,但仍然有边框。

为什么它会这样工作,有没有解决这个问题的方法? 我不可能是唯一一个希望能够设置窗口分辨率的人,无论您使用什么计算机,您设置的大小都是您可以绘制的 DRAW AREA。

【问题讨论】:

  • 不确定你是否想要GetClientRect。它获取您可以绘制的部分,并排除边框/标题栏/等..
  • rect.right - rect.right?你确定吗?
  • GetWindowRect() 和 GetClientRect() 都返回相同的结果。
  • 我的意思是 rect.right - rect.left。
  • GetClientRect() 不应返回与 GetWindowRect() 相同的结果。我认为您在问题中遗漏了一些重要的细节。您是否自定义绘制窗口边框?你用的是航空主题吗?你还记得在你的窗口过程中调用 DefWindowProc 吗?

标签: c++ window gdi createwindow


【解决方案1】:

我用这个方法,现在可以了:

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

}

【讨论】:

    【解决方案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 就可以直接填充到::CreateWindow() 调用中。但令我惊讶的是,leftbottom 字段变为负数。

    【讨论】:

      【解决方案3】:

      我仍然认为您没有提供足够的信息来解决您的问题,但这里有一个完整的程序(基本上)可以满足您的需求。您可以将其与您自己的进行比较,看看您哪里出错了。

      #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。为了将来参考,“您可以绘制的区域”称为客户区。

      【讨论】:

      • 我的窗口定义为 480x240 在运行时是:452x232。那就是“客户区”,那么为什么要定义一个应该在“上”绘制的窗口,但您却没有得到实际设置的确切值呢?这种语言很烦人。
      • 我很欣赏它一开始会让人困惑,但是当您熟悉 Win32 API 时它会更有意义。请记住,CreateWindow 接受 窗口 的大小而不是其 客户区 的大小。
      • 是的,这令人困惑。尤其是当您想在窗口上绘制网格之类的东西时。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多