如何获得需要在 OnPaint() 事件中绘制的确切区域?

tig*_*rou 5 c# gdi+ paint winforms

WinForm应用程序中,当订阅OnPaint()事件时,PaintEventArgs提供一个ClipRectangle属性来定义要绘制的区域。

当窗体垂直或水平调整大小时,它给出要绘制的最小矩形。

在此处输入图片说明

但是当窗口在两个方向上调整大小时,有几个区域需要绘制(一个在右边,一个在底部)和OnPaint事件合并它们。它会产生一个与大小相同的矩形Form(因此一切都被重绘)。我想要的是单独的区域(图片上的两个矩形)

在此处输入图片说明

我知道GDI+自动剪辑不需要绘制的东西(东西在两个矩形之外,不仅仅是ClipRectangle),但我想最大限度地减少GDI+调用(OnPaint由于许多GDI+调用,我在绘制事件时已经有性能问题,这不是过早的优化)

Han*_*ant 3

Windows 中的绘画是由 WM_PAINT 消息处理程序启动的。它必须调用 BeginPaint() 来获取有关需要绘制的内容的信息。它返回一个 PAINTSTRUCT 类型的结构,它看起来像这样:

typedef struct tagPAINTSTRUCT {
  HDC  hdc;
  BOOL fErase;
  RECT rcPaint;              // <=== here
  BOOL fRestore;
  BOOL fIncUpdate;
  BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT;
Run Code Online (Sandbox Code Playgroud)

rcPaint 成员是从 Graphics.ClipRectangle 获得的成员。Graphics.Clip 和 Graphics.ClipBounds 属性不相关,只有当您通过分配 Clip 属性有意剪辑自己时,它们才起作用。

显然,Windows 本身并不让您知道您所要求的是什么。rcPaint 是一个RECT,一个简单的矩形。Windows 只跟踪脏矩形,而不跟踪区域。InvalidateRect() 添加的新矩形会与现有矩形合并,您确实很容易得到整个客户区。

解决此问题的唯一合理方法是关注 ResizeBegin 和 ResizeEnd 事件。当您得到 ResizeBegin 时,您就知道用户正在拖动窗口边缘或角落。您可以使用这些知识来优化绘画,跳过导致模态调整大小循环工作不佳的昂贵部分。