在 OnPaint() 事件中,如何检查给定的矩形是否与无效区域相交?

In OnPaint() event, how to check if a given rectangle intersects with the invalidated region?

在 Winforms 中,可以创建一个非矩形区域并以这种方式使其无效:

Region region = new Region(new Rectangle(...));
region.Union(new Rectangle(...));                   
Invalidate(region);     

那么在OnPaint()事件中,只会重新绘制上面失效的区域:

protected override void OnPaint(PaintEventArgs e)
{   
    //will only repaint the region invalidated above
    //even if ClipRectangle area is bigger than that
    e.Graphics.FillRectangle(Brushes.Blue, e.ClipRectangle); 
}

OnPaint() 事件中,有没有办法检查给定的矩形是否与无效区域相交?

我可以使用 rectangle.Intersect(e.ClipRectangle) 但这可能会产生误报。

编辑:看来我想要的是可以使用 GetUpdateRgn Win32 函数(据我所知,没有与该函数直接等效的 Winforms)

private List<Rectangle> rectangleList;    

当你无效时,你设置你的矩形列表:

rectangleList = getRectangles(...);
Region region = new Region(new Rectangle(...));
foreach(Rectangle rect in rectangleList)
{
    region.Union(rect);  
}                 
Invalidate(region);     

然后在 paint 方法中,检查 rectangleList 中的任何 Rectangle 是否相交,然后清除它:

protected override void OnPaint(PaintEventArgs e)
{   
    bool intersection = false;
    foreach(Rectangle rect in rectangleList)
    {
        if(e.ClipRectangle.Intersect(rect) 
        {
            intersection = true;
            break;
        }
    } 

    if(intersection)
    {
        rectangleList.Clear();
        DoIntersectionStuff();
    }
    else
    {
        DoNonIntersectionStuff();
    }
}

我回答我自己的问题:

在调用BeginPaint()之前,可以通过在WM_PAINT事件中调用GetUpdateRgn()函数来获取更新区域。 要知道矩形是否在区域内,使用 IsVisible() 方法。这是一个 GDI api 调用(不像 Rectangle.Intersect()),所以它通常和直接调用 GDI 绘图函数一样慢(例如:DrawText()),并在必要时让 GDI 执行丢弃工作.

private Region region;    
protected override void WndProc(ref Message m) 
{   
    switch (m.Msg)
    {
        case WM_PAINT:
            region = null;
            IntPtr hrgn = CreateRectRgn(0, 0, 0, 0);
            try
            {
                int result = GetUpdateRgn(Handle, hrgn, false);
                if (result == SIMPLEREGION || region == COMPLEXREGION)
                {
                    region = Region.FromHrgn(hrgn); 
                }
            }
            finally
            {
                DeleteObject(hrgn);
            }
            break;                
    } 
    base.WndProc(ref m);
}

protected override void OnPaint(PaintEventArgs e)
{       
    var rectangle = ...
    if (region != null && region.IsVisible(rectangle))
    {
        //...
    }
}

这是本机 win32 函数声明:

[DllImport("gdi32.dll")]
static extern IntPtr CreateRectRgn(int left, int top, int right, int bottom);

[DllImport("user32.dll")]
static extern int GetUpdateRgn(IntPtr hWnd, IntPtr hRgn, bool bErase);

[DllImport("gdi32.dll")]
static extern bool DeleteObject(IntPtr hObject);

const int WM_PAINT = 0x000F;
const int SIMPLEREGION = 2;
const int COMPLEXREGION = 3;