使用 Winform 绘图

发布于 2024-12-28 19:15:55 字数 330 浏览 1 评论 0原文

我想获得一些 WinForm Graphics 知识,因此我正在将我的小型 2D 编辑器从 XNA 重写为仅 WinForm Graphics。

现在,我为图块集创建了一个新的 UserControl,但正如我所见,Paint 方法仅在控件初始化时调用。由于我想永久地重新绘制我的控件(或者至少通过 MouseOver 事件来节省一些性能),我听说 Invalidate() 方法让 Control 重新绘制自身,但这方式性能太差了。

有什么方法可以让我的 UserControl 通过代码进行自我绘制,而不会出现这些性能问题?

I want to get myself a bit of WinForm Graphics knowledge, so I'm rewriting my small 2D editor from XNA to WinForm Graphics-only.

Now, I made myself a new UserControl for the tileset, but as I've seen, the Paint method is only called at the initialization of the control. Since I want to permanently repaint my control (or at least via MouseOver event to save a bit of performance), I heard the Invalidate() method gets the Control to repaint itself, but that is way too unperformant.

Is there any way to let my UserControl paint itself via code, without having these performance-issues?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心头的小情儿 2025-01-04 19:15:55

Paint 方法不仅仅仅在控件初始化时调用。每次需要重新绘制控件时都会调用它。当然,这是在首次创建控件时发生的。当您的应用程序最小化然后恢复时,当另一个窗口移动到您的应用程序上并遮盖其内容然后被删除时,也会发生这种情况。当您使用 Invalidate 方法或等效方法使控件的工作区无效时,也会发生这种情况。这是在 Windows 开发早期作为性能优化而完成的 — 无需重新绘制未更改的内容!

如果你想强制重新绘制控件,你应该调用 Invalidate 方法 并指定要重新绘制的客户区的特定区域。

我不知道你所说的“这方式表现太差”是什么意思。 Invalidate 方法不可能慢。它所做的只是设置一个标志,告诉 Windows 您的控件在空闲时需要重绘(不处理任何其他消息)。

如果您想强制 Windows 立即重新绘制控件(无需等待其空闲;Windows 早期内置的另一个性能优化),请调用 Update 方法,强制立即重绘所有无效区域。

唯一可能变慢的原因是您的绘图代码在Paint事件处理程序方法内变慢。显然,如果没有先看到代码,我就无法告诉您如何优化该代码。


是否有办法让我的 UserControl 通过代码自行绘制,而不会出现这些性能问题?

Paint 事件正是控件应如何以及在何处进行自我绘制。这就是它存在的原因。

如果您Paint事件中进行绘制,则下次重新绘制控件时,您绘制的任何内容都将被删除(如前所述,这可能发生在对任意数量的预期和意外事件的响应)。

但有时,将临时对象绘制到控件的工作区中是有意义的(例如显示一个拖动矩形以响应 MouseDown 事件)。在这种情况下,您可以获得 Graphics 类的实例(通常作为参数传递给 Paint 事件处理程序方法,并在其上调用方法来执行以下操作)您的绘图)随时。您可以通过调用 CreateGraphics< 来完成此操作控件上的 /code> 方法,它返回一个 Graphics 对象。然后,您可以在获得的 Graphics 对象中进行绘制,就像在 Paint 事件处理程序方法中一样。

显然,这不能/不会比 Paint 事件处理程序方法内的绘制代码更快(如果这实际上是罪魁祸首),但它会导致屏幕更新< em>立即,而不是每当控件空闲且不处理任何其他消息时。

我将再次重申,这种方法应该用于提供立即和临时反馈,因为下次重绘控件时您绘制的所有内容都将被删除。发生这种情况时,将引发 Paint 事件,并且该方法处理程序内的代码将运行,该代码不知道您在其他一次性场合绘制的内容。这就是为什么一切都应该发生在 Paint 事件处理程序方法内,并且您应该在以下情况下调用 Invalidate (也许,尽管不常见,Update):其他一些事件使得有必要重新绘制。

The Paint method is not only called at the initialization of the control. It is called every time that the control needs to be repainted. This, of course, happens when the control is first created. It also happens when your application is minimized then restored, when another window is moved over your app that obscures its contents and then removed, and so on. It also happens when you invalidate the control's client area using the Invalidate method or equivalents. This was done early in the development of Windows as a performance optimization—there's no need to repaint something that hasn't changed!

If you want to force the control to be repainted, you should call the Invalidate method and specify a particular region of the client area to be repainted.

I have no idea what you mean about "that is way too unperformant". It's impossible for the Invalidate method to be slow. All it does is set a flag that tells Windows your control needs to be redrawn whenever it is idle (not processing any other messages).

If you want to force Windows to repaint your control immediately (without waiting for it to be idle; another performance optimization built into Windows from the early days), call the Update method, which forces an immediate redraw of all invalidated regions.

The only way it could be slow is if your drawing code is slow inside of the Paint event handler method. And obviously I can't tell you how to optimize that code without seeing it first.


Is there anyway to let my UserControl paint itself via code, without having these performance-issues?

The Paint event is precisely how and where controls should paint themselves. That's why it's there.

If you don't paint in the Paint event, anything that you paint will be erased the next time that the control is repainted (which, as mentioned earlier, can happen in response to any number of expected and unexpected occurrences).

Sometimes, though, it makes sense to paint temporary objects into the control's client area (such as showing a drag rectangle in response to a MouseDown event). In that case, you can obtain an instance of the Graphics class (which is typically passed as an argument to your Paint event handler method, and on which you call methods to do your drawing) at any time. You do this by calling the CreateGraphics method on your control, which returns a Graphics object. You then draw into/onto the Graphics object obtained just as you would inside of the Paint event handler method.

Obviously this can't/won't be any faster than the drawing code inside of the Paint event handler method (if that is in fact the culprit), but it will cause the screen to be updated immediately rather than whenever the control is idle and not processing any other messages.

I'll reiterate again that this approach should be used only to provide immediately and temporary feedback, as everything you draw will be erased the next time that the control is redrawn. When that happens, the Paint event is raised, and your code inside that method handler runs, which doesn't know anything about what you drew on some other one-off occasion. That's why everything should happen inside of the Paint event handler method, and you should call Invalidate (and perhaps, though not usually, Update) when some other event makes it necessary to repaint.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文