有时我需要控件的自定义外观。或者做很多定制绘画。我知道我可以使用 OnPaint
来做到这一点(请参阅: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.onpaint.aspx )
使用 OnPaint
在 .net 应用程序上自定义绘制内容的正确方法是什么?为了保持应用程序的优化并将渲染时间保持在最短的水平,我需要牢记哪些规则?
注意:我时常看到并经历过许多 OnPaint 的低效使用,因此我创建了此问答。
最佳答案
要有效地使用 OnPaint
,您必须了解以下几点:
- 控件的
OnPaint
,例如Form1
的,每次绘制控件时都会执行(duhh...) - 每次绘制
Form1
的子控件时,都会执行Form1
的OnPaint
。例如如果使用Form1
的OnPaint
在Form1
的右上角绘制一个点,而Form1 上有 150 个子控件
,该点将被绘制至少 150 次!它大大增加了渲染时间。特别是如果您在OnPaint
中进行大量自定义绘图和计算。- 因此,作为一项规则,当控件具有一个或多个子控件时,控件的
OnPaint
中绝对不能有任何逻辑。相反,您应该创建一个自定义控件,它不再包含任何子控件,而是完成绘制工作。并将其作为子控件放置在父控件上需要自定义绘图的位置。 - 每当将控件添加到父控件上时,父控件都会重绘。如果您将很多控件放在另一个控件上,例如如果
Form1
上有复选框的大型结果集,则在添加子控件之前必须使用Form1.SuspendLayout()
(请参阅: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout.aspx )。添加完控件后,还有Form1.ResumeLayout()
。这会暂时抑制OnPaint
事件,并减少渲染时间。 - 透明度总是会增加渲染时间。
- 以组件之间没有背景的方式放置组件,可以减少父控件中
OnPaint
事件的数量。例如。将 4 个文本框放在彼此下方,以便它们互相接触。因此,它们之间没有背景,并且控件全部在一个OnPaint
事件中绘制,而不是在 4 个OnPaint
事件中绘制。当然,这并不总是可行,因为您不想将所有组件并排粘合。但如果性能比外观更重要,例如在某种大型自定义“数据网格”中,那么这是值得做的。 - 切勿在 OnPaint 事件中更改控件的位置或大小,因为这会调用新的 OnPaint 事件。如果必须重新定位/调整控件大小,则必须在调用
OnPaint
之前将其添加到代码中的其他位置。例如,将重定位/调整大小代码放置在OnLayout
或OnResize
或类似事件中。如果您仍然认为必须将重定位/调整大小代码放在OnPaint
事件中才能使您的应用程序正常工作,那么您就错了,您需要修改代码的逻辑。 - 在自身类之外的控件上调用 Refresh() 之前,请先考虑 System.Math.Pow(2, 2) 次。如果您有调用刷新的冲动,您可能需要新的事件和事件处理程序来与您愿意显示的内容保持同步。 Invalidate() 也是如此。
- 要检查您的绘图是否高效,您可以执行以下操作。 1. 打开您的应用程序 2. 在最顶层父级中的 OnPaint 上放置一个制动点 3. 最大化窗口,使其覆盖您的应用程序。 4. 再次最小化窗口,您的应用程序将逐个控件重绘控件。如果事情被重复绘制,那么您的应用程序逻辑就犯了错误。
- 因此,作为一项规则,当控件具有一个或多个子控件时,控件的
好吧,我想就这些了,如果想到我忘记的事情,我会更新这个问答。如果我忘记了什么,或者犯了一个错误,我很乐意记下它!
希望这能让某人在 .Net 中使用自定义绘制内容方面取得先机,因为我前段时间一直在寻找此信息。
关于.net - 在 .Net 应用程序中使用 OnPaint 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13652568/