在 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;
在 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;