(Windows API) WM_PAINT 鼠标问题

发布于 2024-08-22 10:25:16 字数 1362 浏览 1 评论 0原文

我创建了一个带有以下标志的窗口来覆盖 d3d 应用程序: WS_EX_TOPMOST | WS_EX_TOPMOST WS_EX_COMPOSITED | WS_EX_COMPOSITED | WS_EX_TRANSPARENT | WS_EX_TRANSPARENT | WS_EX_LAYERED 我继续对窗口进行颜色键控以实现透明性,一切顺利。 然而,一旦我开始使用 GDI 在其上绘图,就发生了一个不可预见的问题:

由于某种原因,当 WM_PAINT 正在进行时,鼠标事件(尤其是移动)没有正确地通过窗口传递,因此看起来好像是鼠标和键盘在执行该操作物质滞后。 FPS 很好,这是一些 API 问题,我怀疑由于某种原因,在 WM_PAINT 正在进行时键盘/鼠标消息没有按应有的方式处理,因为计时器设置得越慢,抖动就越少。

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

 switch(msg)
 {
  case WM_DESTROY:
  {
          KillTimer(hwnd, ID_TIMER);
          PostQuitMessage(0);
          break;
         }
  case WM_CREATE:
  {
   SetTimer(hwnd, ID_TIMER, 10, NULL);
   break;
  }
  case WM_TIMER:
  {
   InvalidateRect(hwnd, 0, 1);
   break;
         }
  case WM_PAINT:
  {
   paint(hwnd);
   break;
  }
 }
 return DefWindowProc(hwnd, msg, wParam, lParam);
}

感谢

void paint (HWND hwnd)
{
 PAINTSTRUCT Ps;
 HDC hdc = BeginPaint(hwnd, &Ps);

 SetBkColor(hdc, RGB(0,0,0));
 SetBkMode(hdc, TRANSPARENT);



 LOGBRUSH log_brush;
 log_brush.lbStyle = BS_NULL;
 HBRUSH handle_brush = CreateBrushIndirect(&log_brush);
 SelectObject(hdc, handle_brush);


..........................................


 DeleteObject(font);
 DeleteObject(pen);
 DeleteObject(handle_brush);

 EndPaint(hwnd, &Ps);
}

您提供的任何帮助。

I created a window with the following flags to overlay a d3d application:
WS_EX_TOPMOST | WS_EX_COMPOSITED | WS_EX_TRANSPARENT | WS_EX_LAYERED
I proceeded with colorkeying the window for transperacy and all worked well.
However once I began drawing on it using GDI an unforeseen problem occurred:

For some reason the mouse events (especially movement) are not passed correctly through the window when WM_PAINT is in progress, and so it appears as though the mouse and the keyboard for that matter lag. the FPS is fine, this is some API problem, I suspect that for some reason the keyboard/mouse messages are not handled as they should while the WM_PAINT is in progress, because the slower the timer is set to the less jerking there is.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

 switch(msg)
 {
  case WM_DESTROY:
  {
          KillTimer(hwnd, ID_TIMER);
          PostQuitMessage(0);
          break;
         }
  case WM_CREATE:
  {
   SetTimer(hwnd, ID_TIMER, 10, NULL);
   break;
  }
  case WM_TIMER:
  {
   InvalidateRect(hwnd, 0, 1);
   break;
         }
  case WM_PAINT:
  {
   paint(hwnd);
   break;
  }
 }
 return DefWindowProc(hwnd, msg, wParam, lParam);
}

and

void paint (HWND hwnd)
{
 PAINTSTRUCT Ps;
 HDC hdc = BeginPaint(hwnd, &Ps);

 SetBkColor(hdc, RGB(0,0,0));
 SetBkMode(hdc, TRANSPARENT);



 LOGBRUSH log_brush;
 log_brush.lbStyle = BS_NULL;
 HBRUSH handle_brush = CreateBrushIndirect(&log_brush);
 SelectObject(hdc, handle_brush);


..........................................


 DeleteObject(font);
 DeleteObject(pen);
 DeleteObject(handle_brush);

 EndPaint(hwnd, &Ps);
}

Thank you for any help you may be able to give.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

等风也等你 2024-08-29 10:25:17

除非有人调用 UpdateWindow 或者输入队列中没有键盘或鼠标消息,否则 WM_PAINT 消息永远不会传递到您的窗口。

一旦您开始处理 WM_PAINT,如果键盘或鼠标消息到达,它只会位于您的队列中,直到您处理完 WM_PAINT。所以你所描述的情况是不可能的。

如果您的 WM_PAINT 代码需要很长时间才能执行,这可能会导致抖动,但您说这不是问题,所以也许这是您对 WM_ERASEBKGND 的处理?我没有看到该代码,但我确实看到当您 InvalidateRect 时,您将 TRUE 作为最后一个参数传递,这意味着您希望擦除背景。

如果您不处理 WM_ERASEBKGND,则 DefWindowProc 将为您使用窗口类中的画笔擦除整个窗口。这可能会导致 Windows 认为窗口的任何部分都是透明的。

如果您希望鼠标消息穿过您的窗口,更可靠的方法是处理 WM_NCHITTEST 消息并在您希望鼠标穿过的位置返回 HTTRANSPARENT。
这基本上就是 WS_EX_TRANSPARENT 样式的工作原理。像这样

case WM_NCHITTEST:
   {
   lRet = DefWindowProc(hwnd, uMsg, wParam, lParam);
   if (HTCLIENT == lRet)
      lRet = HTTRANSPARENT;
   }

如果你的窗口没有非客户区,那么你可以跳过对DefWindowProc的调用。

WM_PAINT messages are never delivered to your window unless someone calls UpdateWindow or there are no keyboard or mouse messages in your input queue.

Once you begin processing WM_PAINT, if a keyboard or mouse message arrives, it just sits in your queue until you are done with WM_PAINT. So What you are describing isn't possible.

If your WM_PAINT code takes a long time to execute, that could cause jerkiness, but you say that's not a problem so perhaps it's your handling of WM_ERASEBKGND? I don't see that code, but I do see that when you InvalidateRect, you are passing TRUE as the last parameter which means that you want the background to be erased.

If you don't handle WM_ERASEBKGND, then DefWindowProc will do it for you erasing your entire window with the brush from from your window class. This could result in windows thinking that no part of your window is transparent.

If you want mouse messages to pass through your window, a more reliable way is to handle the WM_NCHITTEST message and return HTTRANSPARENT where you want the mouse to pass through.
This is basically what how the WS_EX_TRANSPARENT style works. like this

case WM_NCHITTEST:
   {
   lRet = DefWindowProc(hwnd, uMsg, wParam, lParam);
   if (HTCLIENT == lRet)
      lRet = HTTRANSPARENT;
   }

If your window has no non-client area, then you can skip the call to DefWindowProc.

仅一夜美梦 2024-08-29 10:25:17

WndProc() 并不总是可重入的。我相信通过主消息泵,鼠标和键盘消息会排队等待您完成之前的 WM_PAINT 消息。相反,如果您要从 WndProc() 调用 SendMessage(),那么您就会看到重新进入。另一种情况是 PostMessage() ,它将消息添加到队列中。如果这是一个问题,也许可以考虑使用 DirectInput 进行鼠标和键盘输入。否则,寻找加快绘图速度的方法。

WndProc() is not always re-entrant. I believe with the main message pump, the mouse and keyboard messages are queued up and waiting for you to finish the prior WM_PAINT message. Conversely, if you were to call SendMessage() from WndProc(), then you are looking at re-entrace. The other case is PostMessage() which would add the message to the queue. Maybe look at using DirectInput for mouse and keyboard input if this is an issue. Otherwise, look for ways to speed up your drawing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文