使多个矩形或区域无效
本文关键字:区域 无效 | 更新日期: 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技术是Win32
的user32
库的包装器。要了解paint事件的背后,您需要了解user32是如何工作的。
消息队列:
windows中的每个进程都有一个消息队列。当属于进程的窗口发生任何事情时,Windows会将事件推送到进程的消息队列中。每个应用程序中都有一个消息循环,它从队列中提取消息(通过调用GetMessage()
)并调度消息(通过呼叫DispatchMessage()调用适当的函数,称为Window Procedure
)。因此,这些消息正在被一个接一个地处理。这意味着在处理一条消息时,不能处理其他消息
这就是为什么当你在表单中进行耗时的操作(不启动新线程)时,应用程序会停止响应:你被困在处理一条消息中(例如按钮的Click
事件),所以应用程序无法处理其他消息(鼠标事件、绘画事件等)
在Windows窗体中,Application.Run
方法运行应用程序的消息循环。消息被传递给控制。WndProc方法和该方法确定要调用的适当OnXxxx
方法(OnKeyPress
、OnMouseMove
、OnResize
等),并且该方法引发相应的事件(KeyPress
、MouseMove
、Rezie
等)。
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
事件。
请按照答案中的链接进行阅读。