使多个矩形或区域无效

本文关键字:区域 无效 | 更新日期: 2023-09-27 17:59:37

我的Invalidate()有问题,因为它在我准备好之前调用了OnPaint。。。当我需要重新绘制一个并且只有一个区域时,Invalidate(new Rectangle(x, y, width, height))可以很好地工作,但我需要做的是创建一个矩形集合以使其无效,然后使用Update()方法重新绘制所有无效区域。我有点迷失在Invalidate()Update()之间:如何使用它们以及什么是干净的方法

我需要做到这一点,因为我正在研究细胞自动机,比如"朗顿蚂蚁"或"康威生命游戏"。小网格不是问题,但对于大尺寸网格(700x500),绘画是一个非常重要的问题。

因此,我的问题是,如何在每次无效时不调用OnPaint而使X个矩形无效,然后调用OnPaint仅刷新指定区域(X个矩形肯定至少为成百上千)?

使多个矩形或区域无效

调用Invalidate方法不会立即引发Paint事件。它只将指定的区域设置为无效,并对绘制事件进行排队。对Invalidate的下一次调用只将该区域添加到先前无效的区域中。仅当队列中没有Paint事件时,它才会放入新的Paint事件。

来自Invalidate方法的备注部分:

调用Invalidate方法不会强制执行同步绘制;若要强制同步绘制,请在调用Invalidate方法后调用Update方法。当在没有参数的情况下调用此方法时,整个客户端区域都会添加到更新区域中。


更多解释:

WindowsForms技术是Win32user32库的包装器。要了解paint事件的背后,您需要了解user32是如何工作的。

消息队列:

windows中的每个进程都有一个消息队列。当属于进程的窗口发生任何事情时,Windows会将事件推送到进程的消息队列中。每个应用程序中都有一个消息循环,它从队列中提取消息(通过调用GetMessage())并调度消息(通过呼叫DispatchMessage()调用适当的函数,称为Window Procedure)。因此,这些消息正在被一个接一个地处理。这意味着在处理一条消息时,不能处理其他消息
这就是为什么当你在表单中进行耗时的操作(不启动新线程)时,应用程序会停止响应:你被困在处理一条消息中(例如按钮的Click事件),所以应用程序无法处理其他消息(鼠标事件、绘画事件等)

在Windows窗体中,Application.Run方法运行应用程序的消息循环。消息被传递给控制。WndProc方法和该方法确定要调用的适当OnXxxx方法(OnKeyPressOnMouseMoveOnResize等),并且该方法引发相应的事件(KeyPressMouseMoveRezie等)。

WM_PAINT:

当程序的窗口需要绘制时(例如,当它第一次显示或从最小化状态恢复时),只有在消息队列中没有针对该窗口的未处理的WM_PAINT的情况下,Windows才会将WM_PAINT消息排入消息队列。此外,只有当队列中没有其他消息时,消息循环才会从队列中提取WM_PAINT消息。MSDN中WM_PAINT页面的Qoute:

当应用程序的消息队列中没有其他消息时,GetMessage返回WM_PAINT消息,DispatchMessage将消息发送到相应的窗口过程。

在Windows窗体中,WM_PAINT转换为引发Paint事件的OnPaint方法。

当您在一个方法中多次调用Invalidate(它调用Win32 InvalidateRect函数)时,Paint事件仍然没有机会被引发。当前正在处理的事件必须完成,同时还应处理同时发送的其他消息,然后引发Paint事件。

请按照答案中的链接进行阅读。