简体   繁体   English

我是否必须继续创建Graphics对象

[英]Do I have to keep creating a Graphics object

I am an old delphi programmer, I am used to creating objects and using them entire time for efficient memory usage. 我是一个老的delphi程序员,我习惯于创建对象并将它们全部用于有效的内存使用。 But in c# (maybe all the tutorials I've ever seen), you are creating stuffs with new every time (thanks to garbage collector!!, let me do the coding).. 但是在c#(也许是我见过的所有教程)中,你每次都在用new东西创建东西(感谢垃圾收集器!!,让我做编码)..

Anyway, I am trying to create a designing software which has lots of drawing. 无论如何,我正在尝试创建一个有很多绘图的设计软件。 My question is: do I have to create a graphics object, or use the protected override void OnPaint(PaintEventArgs e) e.Graphics every painting event.. because when I create a graphic object and then resize the control that I draw on, the graphic object that I created, has that clipping problem and only draws old rectangle region.. 我的问题是:我是否必须创建一个图形对象,或者使用protected override void OnPaint(PaintEventArgs e) e.Graphics每个绘制事件..因为当我创建一个图形对象然后调整我绘制的控件时,我创建的图形对象,有剪切问题,只绘制旧的矩形区域..

thanks 谢谢

Caching objects makes sense when the object is expensive to create, cheap to store and relatively simple to keep updated. 当对象创建昂贵,存储便宜并且保持更新相对简单时,缓存对象是有意义的。 A Graphics object is unique in that none of these conditions are true: 没有这些条件都为真Graphics对象是独一无二的:

  • It is very cheap to create, takes well less than a microsecond. 它的制作非常便宜,只需不到一微秒。
  • It is very expensive to store, the underlying device context is stored in the desktop heap of a session. 存储起来非常昂贵,底层设备上下文存储在会话的桌面堆中。 The number of objects that can be stored is small, no more than 65535. All programs that run in the session share that heap. 可以存储的对象数量很少,不超过65535.在会话中运行的所有程序共享该堆。
  • It is very hard to keep updated, things happen behind your back that invalidates the device context. 保持更新非常困难,背后的事情会使设备上下文无效。 Like the user or your program changing the window size, invalidating the Graphics.ClipBounds property. 与更改窗口大小的用户或程序一样,使Graphics.ClipBounds属性无效。 You are wasting the opportunity to use the correct Graphics object, the one passed to you in a Paint event handler. 您正在浪费机会使用正确的Graphics对象,即在Paint事件处理程序中传递给您的对象。 Particularly a bug factory when you use double-buffering. 特别是当你使用双缓冲时的bug工厂。

Caching a Graphics object is a bug. 缓存Graphics对象是一个错误。

If you want to draw on the surface always use the Graphics object from the Paint event! 如果要在曲面上绘图,请始终使用Paint事件中的Graphics对象!

If you want to draw into a Bitmap you create a Graphics object and use it as long as you want. 如果要绘制到Bitmap可以创建Graphics对象并根据需要使用它。

For the Paint event to work you need to collect all drawing in a List of graphic actions; 要使Paint事件起作用,您需要收集图形操作List的所有图形; so you will want to make a nice class to store all parameters needed. 所以你会想要一个很好的类来存储所需的所有参数。

In your case you may want to consider a mixed approach: Old graphic actions draw into a bitmap, which is the eg BackgroundImage or Image of your control 在您的情况下,您可能需要考虑混合方法:旧图形操作绘制到位图,例如BackgroundImage或控件的Image

Current/ongoing drawing are done on the surface. 当前/正在进行的绘图在表面上完成。 This amounts to using the bitmap as a cache , so you don't have to redraw lots of actions on every little change etc 这相当于使用位图作为缓存 ,因此您不必在每次微小的更改等上重绘大量操作

This is closely related to your undo/redo implementation. 这与您的undo/redo实现密切相关。 You could set a limit and draw those before into a Btimap and those after onto the surface.. 您可以设置一个限制,然后将它们绘制到Btimap中,然后绘制到表面之后。

PS: You also should rethink your GC attitude. PS:你也应该重新思考你的GC态度。 It is simple, efficient and a blessing to have around. 它简单,高效,是一种祝福。 (And, yes, I have done my share of TP&Delphi, way back when they were affordable..) - Yes, we do the coding, but GC is not about coding but about house keeping. (而且,是的,我已经完成了TP&Delphi的份额,当它们价格合理的时候就可以了。) - 是的,我们进行编码,但GC并不是关于编码而是关于管家。 Boring at best.. (And you can always design to avoid it, but not with a Graphics object in a windows system.) 最好无聊..(你可以设计避免它,但不能在Windows系统中使用Graphics对象。)

A general rule for every class that implements IDisposable is to Dispose() it, as soon as possible. 实现IDisposable的每个类的一般规则是尽快Dispose()它。 Make sure you know about the using(...){} statement. 确保您了解using(...){}语句。

For drawing in WinForms (GDI+) the best practice is indeed to use the Graphics object from PaintEventArgs. 对于WinForms(GDI +)中的绘图,最佳实践确实是使用PaintEventArgs中的Graphics对象。 And because you didn't create that one, do not Dispose() it. 因为你没有创建一个,请不要将其()它。 Don't stash it either. 也不要藏匿它。

I have to completely disagree with other more experienced members here who say it's no big deal or in fact better to recreate the Graphics object over and over. 我必须完全不同意其他更有经验的成员,他们说这不是什么大不了的事,或者实际上更好地重复一遍又一遍地重新创建Graphics对象。

The HDC is a pointer to a HDC__ struct, which is a struct with one member, "int unused". HDC是指向HDC__结构的指针,该结构是一个具有一个成员“int unused”的结构。 It's an absolute waste and stupidity to create another instance/object every time drawing needs to be done. 每次需要绘制时,创建另一个实例/对象绝对浪费和愚蠢。 The HDC is NOT large, it's either 4 or 8 bytes, and the struct it points to is in nearly all cases 4 bytes. HDC并不大,它是4或8个字节,它指向的结构几乎在所有情况下都是4个字节。 Furthermore, on the point that one person made, it doesn't help that the graphics object be made with the "static" keyword at the beginning of the WndProc() before the switch, because the only way to give the Graphics object a device context or handle to paint on is by calling its constructor, so "static" does nothing to save you from creating it over and over again. 此外,就一个人所做的那样,在切换之前的WndProc()开头用“static”关键字创建图形对象没有帮助,因为给Graphics对象一个设备的唯一方法上下文或绘制的句柄是通过调用它的构造函数,因此“静态”不会阻止你反复创建它。

On top of that Microsoft recommends that you create a HDC pointer and assign it to the same value PAINTSTRUCT already has, every, single WM_PAINT message it sends. 最重要的是,Microsoft建议您创建一个HDC指针并将其分配给PAINTSTRUCT已经拥有的相同值,它发送的每个单个WM_PAINT消息。

I'm sorry but the WinAPI in my opinion is very bad. 对不起,我认为WinAPI非常糟糕。 Just as an example, I spent all day researching how to make a child WS_EX_LAYERED window, to find out that in order to enable Win 8 features one has to add code in XML with the OS's ID number to the manifest. 作为一个例子,我花了一整天时间研究如何创建一个子WS_EX_LAYERED窗口,以发现为了启用Win 8功能,必须将带有操作系统ID号的XML代码添加到清单中。 Just ridiculous. 太荒谬了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在图形对象转换后在图形对象中的任何位置绘制 - How do i draw anywhere in a graphics object after it is transformed 创建新对象时绘制图形 - Drawing graphics when creating a new object 如何在PrintPage事件中将Graphics对象转换为Bitmap对象? - How do I convert a Graphics object to a Bitmap object, inside PrintPage event? MVVM,我必须将每个命令保留在自己的类中吗? - MVVM, do I have to keep each command in own class? 如何保持不同的线程有自己的变量计算? - How do I keep different threads to have their own variable calculations? 我如何传递MemberInitExpression对象 - How do I have to pass a MemberInitExpression object 如何在C#中将具有透明截面的图像绘制到Graphics对象? - How do I draw an image with a transparent section to a Graphics object in C#? 如何以十六进制颜色在图形对象上绘制实心圆? - How do I draw a filled circle onto a graphics object in a hexadecimal colour? 以ac#形式使用painteventargs; 如何将更大的图像绘制到Graphics对象(以及滚动条)? - using painteventargs in a c# form; how do I draw a larger image to the Graphics object (with scrollbars as well)? 在 C# 中创建对象时如何使用 if 语句? - How can i have an if statement when creating an object in c#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM