2

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

我需要实现这一点,因为我正在研究诸如“兰顿的蚂蚁”或“康威的生命游戏”之类的元胞自动机。小网格不是问题,但是对于大尺寸的网格(700x500),绘画是一个非常重要的问题。

所以我的问题是如何使 X 矩形无效而不OnPaint在每次失效时调用,然后调用OnPaint以仅刷新指定区域(X 矩形将 = 至少数百,数千肯定)?

4

1 回答 1

6

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

从方法的备注部分Invalidate

调用 Invalidate 方法不会强制同步绘制;要强制同步绘制,请Update在调用 Invalidate 方法后调用该方法。不带参数调用此方法时,会将整个客户区添加到更新区域。


更多解释:

Windows Forms 技术是Win32'suser32库的包装器。要了解绘制事件的底层原理,您需要了解 user32 的工作原理。

消息队列:

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

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

WM_PAINT:

当需要绘制程序的窗口时(例如,当它首次显示或从最小化状态恢复时),WindowsWM_PAINT将消息排队到消息队列中,前提是消息队列中没有未处理WM_PAINT的窗口。此外,消息循环仅WM_PAINT在队列中没有其他消息时才从队列中提取消息。来自WM_PAINTMSDN 页面的引用:

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

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

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

请按照答案中的链接仔细阅读。

于 2013-02-16T18:08:29.573 回答