简体   繁体   English

使用Delphi绘制和清除桌面画布

[英]Drawing and clearing the desktop canvas with Delphi

I'm trying to draw over the whole screen by using the desktop canvas and painting to it directly. 我正在尝试通过使用桌面画布并直接对其进行绘制来绘制整个屏幕。 The problem is I can't clear that desktop canvas. 问题是我无法清除该桌面画布。 I've tried setting the canvas.pen.style to psNotXOR and draw over the old image but unfortunately, this is not reliable enough and some left overs are still present in some conditions. 我尝试将canvas.pen.style设置为psNotXOR并绘制旧图像,但是不幸的是,这不够可靠,在某些情况下仍存在一些剩余物。

My need is to draw a selection rectangle around a window / control when the mouse is over it. 我需要在鼠标悬停在窗口/控件周围时在其周围绘制一个选择矩形。

You don't write on what OS you have problems with the artefacts after clearing. 清除后,您无需再写关于哪个工件存在问题的操作系统。

At least with desktop composition activated it is a very bad idea to draw directly to the desktop and to do XOR painting (see "Drawing To and Reading From the Screen -- Baaaad!" in this blog post ). 至少在激活桌面合成的情况下,直接绘制到桌面上并进行XOR绘画是一个非常糟糕的主意(请参阅本博客文章中的 “从屏幕上绘画并阅读-Baaaad!”)。 Apart from the negative performance implications you can't be sure what other painting happens at the same time and what effects and animations alter the displayed content, so a simple XOR may not be enough to completely erase everything. 除了对性能的负面影响外,您无法确定同时会发生其他绘画以及哪些效果和动画会改变显示的内容,因此,简单的XOR可能不足以完全擦除所有内容。

One possible way to implement it would be a transparent overlay window of desktop size, and to draw your rubber band selector over that. 一种可能的实现方式是在桌面上放置一个透明的叠加窗口,并在其上绘制橡皮筋选择器。 Invalidating the whole window if the size changes should be enough, no need to erase the old selection line. 如果大小更改应该足够,则使整个窗口无效,无需擦除旧的选择线。 If the overlay is removed the line will be gone too. 如果移除覆盖层,该线也将消失。 Desktop composition will make sure that no flicker occurs. 桌面合成将确保不会发生闪烁。 However, switching applications while selecting an area will be problematic, you need to catch this and immediately cancel the selection. 但是,在选择区域时切换应用程序会出现问题,您需要抓住这一点并立即取消选择。

Edit: 编辑:

I just tested it with Delphi 2009, and with the following test app: 我刚刚使用Delphi 2009和以下测试应用程序对其进行了测试:

  • a form with FormStyle set to fsStayOnTop and with AlphaBlend set to True FormStyle设置为fsStayOnTopAlphaBlend设置为True的表单
  • with an overridden CreateParams() method to add the WS_EX_TRANSPARENT extended style flag 与重写的CreateParams()方法一起添加WS_EX_TRANSPARENT扩展样式标志

I can pass all mouse clicks through to the underlying windows while being able to draw into a window on top of them. 我可以将所有鼠标单击传递到基础窗口,同时能够在它们之上绘制一个窗口。 This should get you started. 这应该使您入门。

I've done some stuff like this in the past and I've never come up with an acceptable solution. 我过去做过类似的事情,但从来没有想过可以接受的解决方案。

Having a think about it though you could send the desktop HWND an invalidate command. 请考虑一下,尽管您可以向桌面HWND发送无效命令。

Because the desktop is a modified listview control you should able to use something like 由于桌面是经过修改的listview控件,因此您应该可以使用类似

procedure InvalidateDesktop;
begin
  RedrawWindow(GetDesktopWindow, 0, 0, RDW_INVALIDATE);

  //if that doesn't work then try this:
  //Sendmessage(GetDesktopWindow, wm_setredraw, 1, 0);
end;

That might do what you want, I haven't tested it as I've just knocked it up for the example. 那可能会满足您的要求,我还没有对其进行测试,因为我只是将它作为示例。

the problem is that Windows won't return me the control behind the mouse 问题是Windows不会向我返回鼠标背后的控件

I think you need to hook the mouse event messages for this - the hooked message then gives you the window handle that the mouse is over. 我认为您需要为此挂钩鼠标事件消息-挂钩消息然后为您提供鼠标悬停的窗口句柄。

Look up SetWindowsHookEx(WH_MOUSE,,,) and MOUSEHOOKSTRUCT. 查找SetWindowsHookEx(WH_MOUSE ,,,)和MOUSEHOOKSTRUCT。

This is how we do it in our app: 这是我们在应用程序中执行的操作:

    FBitmap.Canvas.Brush.Color := clWhite;
    FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM