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.
My need is to开发者_C百科 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). 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.
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:
- a form with
FormStyle
set tofsStayOnTop
and withAlphaBlend
set toTrue
- with an overridden
CreateParams()
method to add theWS_EX_TRANSPARENT
extended style flag
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.
Because the desktop is a modified listview control you should able to use something like
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
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.
This is how we do it in our app:
FBitmap.Canvas.Brush.Color := clWhite;
FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect);
精彩评论