调整 window 的大小会导致位图被覆盖

Resizing the window results in bitmaps being overwritten

我一直在 Visual C++ 中处理位图和渲染,遇到了一个奇怪的问题。

我正在尝试让绘图区域在用户调整 window 大小时调整大小。现在,不仅扩大 window 不会扩大可见绘图区域(白色边框出现在原始 window 边界之外),而且更改 window 大小似乎很麻烦用我的位图。

这是游戏启动时的样子:

更改 window 的宽度或高度后,紫色字符现在已被橙色字符替换。

最后,三个都变成了蓝色。

如果我继续下去,所有字符都会被绿草背景位图覆盖。

它似乎以位图呈现的相反顺序发生。添加第二行字符确认它在呈现代码中不是问题 - 内存中的实际位图正在以某种方式改变。删除调整大小代码会导致位图错误停止重现。

当我尝试重新初始化设备上下文时,几乎可以肯定这是我的调整大小代码中的一个错误,但我不确定它是什么。

这里是相关的设置代码:

HBITMAP player_blue = (HBITMAP) LoadImage (NULL, L"Images/test_player_blue.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP player_orange = (HBITMAP) LoadImage (NULL, L"Images/test_player_orange.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP player_purple = (HBITMAP) LoadImage (NULL, L"Images/test_player_purple.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
HBITMAP background_bitmap = (HBITMAP) LoadImage (NULL, L"Images/test_background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);

  HDC hdc = GetDC (Window);
  HDC hdc_temp = CreateCompatibleDC (hdc);
  HBITMAP bitmap_buffer = CreateCompatibleBitmap (hdc, resize.screen_width, resize.screen_height);
  SelectObject (hdc, bitmap_buffer);

来自 wWinMain() 的主循环:

  while (!Exit)
    {
    while (PeekMessage (&msg, nullptr, 0, 0, PM_REMOVE))
      {
      DispatchMessage(&msg);
      }
    Render ();
    }

调整大小完成的回调函数:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
  switch (message)
    {
    case WM_SIZE:

      RECT window_rect;
      if (GetWindowRect (Window, &window_rect))
        {
        hdc = GetDC (Window);
        hdc_temp = CreateCompatibleDC (hdc);
        bitmap_buffer = CreateCompatibleBitmap (hdc, resize.screen_width, resize.screen_height);
        SelectObject (hdc, bitmap_buffer);

        screen_width = window_rect.right - window_rect.left;
        screen_height = window_rect.bottom - window_rect.top;
        }
      break;

    default:
      return DefWindowProc(hWnd, message, wParam, lParam);
    }
  return 0;
  }

实际通过BitBlt()渲染:

void Render ()
  {
  SelectObject (hdc_temp, background_bitmap);
  BitBlt (hdc, 0, 0, 800, 600, hdc_temp, 0, 0, SRCCOPY);

  SelectObject (hdc_temp, player_blue);
  BitBlt (hdc, 0, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
  SelectObject (hdc_temp, player_orange);
  BitBlt (hdc, 126, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
  SelectObject (hdc_temp, player_purple);
  BitBlt (hdc, 252, 0, 126, 126, hdc_temp, 0, 0, SRCCOPY);
  }

正如 Ken 所说,您正在泄露宝贵的 GDI 资源。再调整一些大小,您的 window 可能会全黑 :)

请参阅https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createcompatibledc :

When you no longer need the memory DC, call the DeleteDC function.您可能不需要在每次调整大小时都创建该 DC。

CreateCompatibleBitmap也是如此。