使用Graphics.FromHwnd在屏幕上绘制和清除内容

4
我正在尝试创建一个程序,用于获取鼠标下窗口的句柄,并显示一些有关它的数据,并在整个窗口上绘制一个填充矩形(非常低的alpha)。我正在使用C#和winforms。
我已经成功地完成了这个程序,但问题是我的绘制方法在BackgroundWorker的循环中,它会在窗口上制作出越来越多的矩形(->带有更高alpha值的矩形),或者当移动鼠标到另一个窗口时,旧的矩形仍然存在。
我还没有找到清除绘制的矩形的方法,因为它只是“存在”于屏幕上,没有绑定到图形对象或其他任何东西。
我已经尝试使用某些本地方法,比如:
[DllImport("User32.dll")]
public static extern Int64 SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
public static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);

[DllImport("user32.dll")]
public static extern bool UpdateWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, RedrawWindowFlags flags);

但以上方法都没有正常工作。其中一些可以工作,但当消息进入队列时,重绘不会立即发生或非常缓慢和出现故障(闪烁等)。

因此,问题是,我如何使用Graphics.FromHwnd(handleOfWindowUnderCursor)“删除”我绘制的矩形?实际上,我认为它在其他窗口上绘制并不重要,因为我以前在尝试消除自己表单上的图纸时也遇到了同样的问题(也从未解决!)。

或者,是否有任何建议,可以在不使用我现在正在使用的方法的情况下在光标下的窗口上绘制和删除矩形?

2个回答

3
我注意到使用绘图时,

Graphics g = Graphics.FromHwnd(form.Handle);

在表单控件下方绘制表单背景。这是您想要实现的吗?

// draw the rectangle
Brush b = new SolidBrush(Color.FromArgb(20, 0, 0, 255));
g.FillRectangle(b, new Rectangle(5, 5, 200, 200));

// clear the rectangle
g.Clear(this.BackColor);

如果我直接在屏幕上绘制,可以使用以下代码:

Graphics g = Graphics.FromHwnd(IntPtr.Zero);

在Windows刷新屏幕后,矩形会立即消失。

有第三种选择,但并不是很直观。

不要绘制一个矩形,而是创建一个带有降低的透明度、TopMost属性设置为true且没有边框的表单。然后将其设置为事件透明:

protected override void WndProc(ref Message m)
        {
            const int WM_NCHITTEST = 0x0084;
            const int HTTRANSPARENT = (-1);

            if (m.Msg == WM_NCHITTEST)
            {
                m.Result = (IntPtr)HTTRANSPARENT;
            }
            else
            {
                base.WndProc(ref m);
            }
        }

之后你需要注意的只有此表单的可见性、位置和大小属性。

我正在尝试创建一个非常简单的截屏程序,它可以对进程窗口进行截屏。我希望它能显示一个轻微的矩形覆盖层,以指示窗口是正确的。也许另一种形式会更容易实现。 - bloodleh

0
 bool change = false;
private void timer1_Tick(object sender, EventArgs e)
    {
        try
        {
            if (change)
            {
                 InvalidateRect(IntPtr.Zero, IntPtr.Zero, true);
                change = false;
            }
            else
            {
                PaintRectangleToScreen();
                change = true;
            }


        }
        catch (System.Exception caught)
        {

            MessageBox.Show(caught.Message);
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接