我有一个动态List of Point,可以随时添加新Point。我想绘制线条以使用不同的颜色连接它们。颜色基于这些点的索引。这是代码:
private List<Point> _points;
private static Pen pen1 = new Pen(Color.Red, 10);
private static Pen pen2 = new Pen(Color.Yellow, 10);
private static Pen pen3 = new Pen(Color.Blue, 10);
private static Pen pen4 = new Pen(Color.Green, 10);
private void Init()
{
// use fixed 80 for simpicity
_points = new List<Point>(80);
for (int i = 0; i < 80; i++)
{
_points.Add(new Point(30 + i * 10, 30));
}
}
private void DrawLinesNormal(PaintEventArgs e)
{
for (int i = 0; i < _points.Count-1; i++)
{
if (i < 20)
e.Graphics.DrawLine(pen1, _points[i], _points[i + 1]);
else if (i < 40)
e.Graphics.DrawLine(pen2, _points[i], _points[i + 1]);
else if (i < 60)
e.Graphics.DrawLine(pen3, _points[i], _points[i + 1]);
else
e.Graphics.DrawLine(pen4, _points[i], _points[i + 1]);
}
}
当我有新的高速进入时,我发现这种方法不够快。有没有办法让它更快?我做了一些研究,有人说使用GraphicsPath可能会更快,但是如何?
[更新]我收集了一些可能的优化:
答案 0 :(得分:5)
在不降低质量或更改为更快的渲染器(GDI,OpenGL,DirectX)的情况下,您无法从代码中挤出更多的速度。但是GDI通常会快得多(可能是2倍),而DirectX / OpenGL可以更快(可能是10倍),具体取决于你所绘制的内容。
使用Path的想法是将许多(在您的示例中为20行)批处理为单个方法调用,而不是将DrawLine调用20次。如果您可以将传入数据排列为绘图例程的正确列表格式,这将使您受益。否则,您将必须将点复制到正确的数据结构中,这将浪费您通过批处理路径获得的大量时间。对于DrawPath,您可能必须从点数组创建GraphicsPath,这可能导致没有时间保存。但是如果你不得不多次绘制相同的路径,你可以缓存它,然后你可以看到净收益。
如果新的点被添加到列表中,但旧点未被删除(即,您总是只是向显示添加新行),那么您将能够使用屏幕外位图来存储到目前为止渲染的线。这样,每次添加一个点时,都会绘制一个行,而不是每次都绘制所有80行。
这完全取决于你想要做什么。
答案 1 :(得分:2)
并没有真正帮助提高性能,但我会将笔放入列表并以这种方式编写所有这些行:
int ratio = _points.Count / _pens.Count;
for (int i = 0; i < _points.Count - 1; i++)
{
e.Graphics.DrawLine(_pens[i / ratio], _points[i], _points[i + 1]);
}
答案 2 :(得分:1)
这与你使用System.Drawing的速度差不多。您可能会使用Graphics.DrawLines()
看到一些增益,但您需要以不同方式格式化数据,以便使用相同的笔一次性绘制一堆线条。我非常怀疑GraphicsPath
会更快。
提高速度的一个可靠方法是降低输出质量。将Graphics.InterpolationMode
设置为InterpolationMode.Low
,Graphics.CompositingQuality
设置为CompositingQuality.HighSpeed
,Graphics.SmoothingMode
设置为SmoothingMode.HighSpeed
,Graphics.PixelOffsetMode
设置为PixelOffsetMode.HighSpeed
和{ {1}}至Graphics.CompositingMode
。
我记得一次速度测试,有人将Graphics与P / Invoke比较为GDI例程,并且对P / Invoke速度快得多,我感到非常惊讶。你可能会检查出来。我会看看我是否能找到这种比较...... 显然这是针对Compact Framework的,所以很可能不适用于PC。
另一种方法是使用Direct2D,如果你有合适的硬件,它可以比GDI更快。
答案 3 :(得分:1)
太晚了,但可能还有人需要解决方案。
我用类似的(但不是完全/相等的)GDI +语法创建了小型库GLGDI +,它在OpenTK上运行:http://code.google.com/p/glgdiplus/
我不确定稳定性,它在DrawString方面存在一些问题(来自OpenTK的TextPrint问题)。但是如果你需要为你的实用程序提升性能(比如我的情况下的级别编辑器),它可以是解决方案。
答案 4 :(得分:0)
你可能想看一下Brush对象,你确实不会接近GDI +程序的实时性能,但只要对象的几何和数量保持不变,你就可以很容易地保持一个不错的fps在合理的范围内。至于画线,我不明白为什么不。
但是,如果你达到了你认为最佳的点,那就是画线......你应该考虑使用不同的图形堆栈,如果你喜欢.NET但是有非OpenMan API等问题DirectX,使用WPF或Silverlight,它非常强大。
无论如何,您可以尝试设置System.Drawing.Drawing2D.GraphicsPath,然后使用System.Drawing.Drawing2D.PathGradientBrush以这种方式应用颜色。这是一个单缓冲的绘制调用,如果你无法获得足够的性能。你将不得不使用其他完全不同于GDI +的东西
答案 5 :(得分:0)
根本不是GDI(+),但解决这个问题的完全不同的方法可能是使用一块内存,将线条绘制到那里,将其转换为Bitmap
对象以立即绘制你的位置需要展示你的台词。
当然,这取决于快速的方式
Bitmap
以显示。我认为不是在.NET Framework中,但可能在第三方库中?对于像这样的东西,Silverlight中没有bitmap writer种吗? (我自己还没有进入Silverlight ......)
至少它可能是开箱即用的方法。希望它有所帮助。
答案 6 :(得分:0)
我认为你必须在绘图后处理笔对象和e.Graphics对象。 如果你在onPaint()中编写drawLine代码,那就更好了。
just override onPaint() method it support better drawing and fast too.