C++ 调整窗口大小时在窗口中绘制会保留未绘制的边框

C++ 调整窗口大小时在窗口中绘制会保留未绘制的边框,c++,winapi,resize,C++,Winapi,Resize,我遇到的问题似乎微不足道,但我找不到解决它的办法。给你。我有一个有一些图形的窗口 为了简单起见,让我们假设它是一个实心的绿色矩形,它填充了窗口的整个客户端区域。我希望这个矩形被重新绘制,并在每次窗口改变大小时填充整个窗口。我原来是这样做的。我发布了来自WM\u SIZE处理程序的WM\u PAINT消息 它可以工作,但如果我快速移动鼠标,我会看到绿色矩形周围有一点未上漆(白色)区域(实际上只有一面或两面,靠近鼠标所在的位置)。我对这个问题的理解是,处理用户输入(鼠标)的系统线程比我的WM_PAI

我遇到的问题似乎微不足道,但我找不到解决它的办法。给你。我有一个有一些图形的窗口

为了简单起见,让我们假设它是一个实心的绿色矩形,它填充了窗口的整个客户端区域。我希望这个矩形被重新绘制,并在每次窗口改变大小时填充整个窗口。我原来是这样做的。我发布了来自WM\u SIZE处理程序的WM\u PAINT消息

它可以工作,但如果我快速移动鼠标,我会看到绿色矩形周围有一点未上漆(白色)区域(实际上只有一面或两面,靠近鼠标所在的位置)。我对这个问题的理解是,处理用户输入(鼠标)的系统线程比我的WM_PAINT消息处理程序工作得更快。这意味着,当我开始绘制一个更新的矩形(其大小取自WM_size)时,鼠标实际上会移动一点,系统会绘制一个新的窗口框架,这与我试图用绿色填充的窗口框架不同。这将在边框旁边创建未填充的区域,边框在调整大小过程中会移动

当我停止调整大小时,绿色最终会填满整个窗口,但在调整大小的过程中,边框附近会出现一些闪烁,这很烦人。为了解决这个问题,我尝试了以下方法

bool finishedPainting;
RECT windowRect;

case WM_PAINT :
    // .....  painting here

  finishedPainting = TRUE;
  break;

case WM_SIZE :
    // .... some actions

    // posting WM_PAINT
  InvalidateRect(hWnd, NULL, FALSE);
  PostMessage(hWnd, WM_PAINT, 0, 0);
  break;

case WM_SIZING :
    // this supposedly should prevent the system from passing
    // new window size to WM_SIZE
  if (!finishedPainting) memcpy((void*)lParam, &windowRect, sizeof(windowRect));
  else {
      // remember current window size for later use
    memcpy(&windowRect, (void*)lParam, sizeof(windowRect));
    finishedPainting = FALSE;
  }
  return TRUE;
它不起作用。作为一个微小的变化,我也尝试了这个

bool  finishedPainting;
POINT cursorPos;

case WM_PAINT :
    // .....  painting here

  finishedPainting = TRUE;
  break;

case WM_SIZE :
  if (!finishedPainting) SetCursorPos(cursorPos.x, cursorPos.y);
  else {
    finishedPainting = FALSE;
    GetCursorPos(&cursorPos);

      // .... some actions

    InvalidateRect(hWnd, NULL, FALSE);
    PostMessage(hWnd, WM_PAINT, 0, 0);
  }
  break;
这也不行。据我所知,问题的解决办法在于以某种方式减慢鼠标速度,使其仅在绘制完成后才移动到屏幕上的下一个位置(拖动窗口的角或侧面)

有什么办法可以做到这一点吗?或者我认为问题和解决方案存在于其他地方的方式存在根本性的问题

//====================================================

更新

我做了一些实验,下面是我的发现

1) 调整大小时,消息的顺序是WM_SIZE-WM_NCPAINT-WM_SIZE-WM_PAINT。我觉得这有点奇怪。我希望WM_尺寸遵循WM_尺寸,不会被WM_NCPAINT打断

2) 在每个消息处理程序中,我都在调整窗口大小的过程中检查窗口的宽度(为简单起见,我只是在更改宽度)。令人惊讶的是,在WM_尺寸中测量的宽度与在WM_尺寸中测量的宽度不同,但与WM_NCPAINT和WM_PAINT中测量的宽度相同。这本身不是一个问题,只是一个可怕的事实

3) 我得出的结论是,在窗口边界附近发生闪烁有两个主要原因。第一个是WM_NCPAINT先于WM_PAINT。想象你正在伸展你的窗户。新的框架将首先出现(WM_NCPAINT首先出现),然后WM_PAINT将填充客户端区域。当新帧已经出现在屏幕上,但它是空的时,人眼会捕捉到短时间。即使您指定不希望在重新绘制之前删除窗口背景,新添加的区域仍然是空的,您可以在一瞬间看到它。当您抓住右侧窗口边缘并将其快速向右移动时,闪烁的原因得到了最好的证明。闪烁效果的另一个原因不太明显,最好在抓取左侧窗口边缘并将其向左移动时看到。在此移动过程中,您将看到沿右边缘的未填充区域。据我所知,这种影响是由此造成的。当用户调整窗口大小时,会执行以下操作:A)发送WM_-NCPAINT以绘制新框架,B)将旧客户端区域的内容复制到新的左上角窗口(在本例中,它移到了左侧),C)发送WM_-PAINT以填充新客户端区域。然而,由于某些原因,在阶段B期间,Windows会沿着右边缘生成那些未填充的区域,尽管看起来不应该这样做,因为旧内容应该保持原样,直到在WM_绘制期间重新绘制


好的,问题仍然存在——如何在调整大小的过程中去除这些人工制品。就我现在所见,使用标准技术和功能是不可能的,因为它们是由Windows在调整大小过程中执行的一系列步骤造成的。交换WM\u NCPAINT和WM\u PAINT可能会有所帮助,但这似乎超出了我们的控制范围(除非有一种简单的方法可以做到这一点,我只是不知道)。

你不应该自己发布或发送WM\u PAINT消息。相反,使用::invalidate使窗口的某些部分无效,并让Windows决定何时发送WM_PAINT消息。

手动发布WM_PAINT或WM_SIZE是个坏主意。但是,你可以做一件奇怪的疯狂的事情,就是在
RECT
WM_SIZE中记录新的调整大小的坐标,使用
MoveWindow
将窗口的大小更改回原来的大小,完成绘制后,使用WM_PAINT消息中的
MoveWindow
再次手动调整其大小

另一个可能的解决方案是,无论屏幕大小是否调整,都要不断用颜色填充窗口。i、 e

// in the WinMain function
if (GetMessage(&msg,NULL,NULL,0))
{
    TranslateMessage(&msg,NULL,NULL);
    DispatchMessage(&msg,NULL,NULL);
}
else
{
     // fill your window with the color in here
}
当然,您也可以将窗口的背景色设置为绿色,而不是自己绘制:

// Before RegisterClass or RegisterClassEx
// wincl is a WNDCLASS or WNDCLASSEX
wincl.hbrBackground = CreateSolidBrush(RGB(50, 238, 50));

Windows是故意这样工作的。通常认为,响应用户(即鼠标)比拥有一个完全最新的绘制窗口更重要

如果总是在WM_PAINT处理程序中绘制整个窗口,则可以通过重写WM_ERASEBKGND处理程序并返回而不做任何操作来消除大量闪烁

如果您确实坚持更喜欢窗口更新而不是鼠标响应,请使用RDW_UPDATENOW标志将invalidate调用替换为重画窗口调用

编辑:你的观察是有意义的。WM_大小调整在调整窗口大小之前进行,以便您有机会修改大小和/或位置。你可以试着画一下我的客户区