我遇到Invalidate()
问题,因为在我准备好之前它会调用OnPaint
...
当我需要重绘一个且只有一个区域时,Invalidate(new Rectangle(x, y, width, height))
工作正常,但我需要做的是创建一个矩形集合以使其无效,然后使用Update()
方法重新绘制所有无效区域。我在Invalidate()
和Update()
之间有点迷失:如何使用它们以及干净的方法是什么。
我需要实现这个目标,因为我正在研究细胞自动机,例如“Langton's ant”或“Conway的生命游戏”。小网格不是问题,但是对于大尺寸网格(700x500),这幅画是一个非常重要的问题。
所以我的问题是如何在没有在每次失效时调用OnPaint
使X矩形无效,然后调用OnPaint
仅刷新指定区域(X矩形将=至少数百,数千肯定) ?
答案 0 :(得分:5)
调用Invalidate
方法不会立即引发Paint
事件。它仅将指定区域设置为无效并对绘制事件进行排队。下一次调用Invalidate
只会将该区域与以前无效的区域相加。只有在队列中没有Paint
事件时,它才会发出新的Paint
事件。
来自Invalidate
方法的备注部分:
调用Invalidate方法不会强制执行同步绘制;要强制执行同步绘制,请在调用Invalidate方法后调用
Update
方法。如果在没有参数的情况下调用此方法,则会将整个客户区添加到更新区域。
更多解释
Windows Forms技术是Win32
的{{1}}库的包装器。要了解paint事件的内幕,您需要了解user32的工作原理。
Windows中的每个进程都有一个message queue。当属于该进程的窗口发生任何事情时,Windows会将事件推送到该进程的message queue。每个应用程序中都有一个message loop,它从队列中提取消息(通过调用GetMessage()
)并调用消息(调用适当的函数,称为Window Procedure
,通过调用{{3} }})。所以消息正在陆续处理。这意味着在处理消息时,不能处理任何其他消息
这就是为什么当你在表单中执行耗时的操作(withoud启动一个新线程)时,应用程序停止respongind:你被困在处理一条消息(例如按钮的user32
事件),所以应用程序无法处理其他消息(鼠标事件,绘画事件等)。
在Windows窗体中,DispatchMessage()方法运行应用程序的消息循环。邮件会传递给Application.Run
方法,此方法会确定要调用的Click
方法(OnXxxx
,OnKeyPress
,OnMouseMove
等),以及该方法提出相应的事件(OnResize
,KeyPress
,MouseMove
等。
当需要绘制程序的窗口时(例如,当它首次显示或从最小化状态恢复时),Windows将WM_PAINT:消息排入消息队列,但前提是没有未处理的WM_PAINT
消息。 3}}用于消息队列中的窗口。此外,仅当队列中没有其他消息时,消息循环才从队列中提取WM_PAINT
消息。来自WM_PAINT
:
当应用程序的消息队列中没有其他消息时,GetMessage返回WM_PAINT消息,并且DispatchMessage将消息发送到适当的窗口过程。
在Windows窗体中,WM_PAINT
page in MSDN会转换为引发WM_PAINT
事件的Rezie
方法。
当您在单个方法中多次调用OnPaint
(调用Win32 Paint
函数)时,Invalidate
事件仍然无法被提升。必须完成正在处理的当前事件,同时应处理同时发送的其他消息,然后引发Paint
事件。
请按照答案中的链接仔细阅读。