2010-06-24 50 views
8

我正在C#/ .Net中创建一个简单的矢量绘图应用程序。该绘图是在一个面板中完成的,但是我没有使用OnPaint()事件 - 事实上,OnPaint()甚至只是调用另一个实际绘制文档中所有内容的方法。不在OnPaint()中绘制时的双缓冲:它为什么不起作用?

我试图添加双缓冲,但是当我将DoubleBuffered设置为true时,闪烁问题更糟。为什么是这样?如果我想双缓冲控件,我是否必须使用提供的Graphics对象在OnPaint()事件中完成所有绘图,而不是使用Panel.CreateGraphics(),然后绘制该对象?

编辑:这是我使用的基本代码。

private void doc_Paint(object sender, PaintEventArgs e) 
{ 
    g = doc.CreateGraphics(); 
    Render(ScaleFactor, Offset); 
}  

private void Render(float ScaleFactor, PointF offset) 
{ 
    foreach (Line X in Document.Lines) { DrawLine(X.PointA, X.PointB, X.Color, X.LineWidth); } 
} 
private void DrawLine(PointF A, PointF B, Color Color, float Width) 
{ 
    Pen p = new Pen(Color, Width); 
    PointF PA = new PointF(((A.X + Offset.X) * ScaleFactor), ((A.Y + Offset.Y) * ScaleFactor)); 
    PointF PB = new PointF(((B.X + Offset.X) * ScaleFactor), ((B.Y + Offset.Y) * ScaleFactor)); 
    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; 
    g.DrawLine(p, PA, PB); 
} 

一般的想法是ScaleFactor和Offset这两个变量是指UI中的缩放级别和平移级别。 g是一个Graphics对象。

+0

你可以在你的面板的paint事件处理程序中发布代码以及它调用的任何函数吗? – Brandi 2010-06-24 19:21:43

+0

是的,而不是有一个全局的图形对象,有一个全局位图。另外,当你有PaintEventArgs时,你不必说“doc.CreateGraphics();”你可以说“e.Graphics”; – Brandi 2010-06-24 19:54:33

+0

如果您不介意ummanaged解决方案看这里:http://stackoverflow.com/questions/2682025/disable-painting-of-the-vscrollbar-in-a-system-windows-forms-richtextbox(接受的答案)这通常对我有用。 – 2010-06-24 20:25:58

回答

28
g = doc.CreateGraphics(); 

那是错误的。如果您绘制到缓冲区中,双缓冲功能才可以工作。 e.Graphics参考的一个。修复:

g = e.Graphics; 

谨防Panel没有双缓冲默认开启。你需要派生自己的。粘贴到一个新的类:

using System; 
using System.Windows.Forms; 

class BufferedPanel : Panel { 
    public BufferedPanel() { 
     this.DoubleBuffered = true; 
     this.ResizeRedraw = true; 
    } 
} 

编译。从工具箱的顶部放下它。

+0

“BufferedPanel”类的+1。我知道至少有两位独立编写完全相同代码的程序员。这应该是框架的一部分。 – Niki 2010-06-24 20:18:08

+0

+1,也不是坚持它的最好想法,最好是将它传递给Render作为参数。 – user7116 2010-06-24 20:43:16

+1

我们在哪里送啤酒......?你在这里救了我很多头痛...... – 2015-11-30 12:03:01

2

就我个人而言,我不打扰DoubleBuffered设置。我只是将所有内容都绘制成位图,然后在绘制事件中在屏幕上绘制位图。

Bitmap BackBuffer; 

private void MainFormSplitContainerPanel1Paint(object sender, PaintEventArgs e) 
{ 
    e.Graphics.Clear(MainFormSplitContainer.Panel1.BackColor); 
    if (BackBuffer != null) 
     e.Graphics.DrawImage(BackBuffer, positionX, positionY, SizeX, SizeY); 
} 
+0

这是一个简单的改变吗​​?我可以在任何有Panel.Graphics引用的位置引用位图吗? – ian93 2010-06-24 19:38:10

+0

这样认为。基本上在我的应用程序中,我有一些函数将分配或绘制与绘制函数无关的位图。请记住,直到调用paint函数时才会看到更改,所以当您想要“刷新”图像时,请调用MainFormSplitContainer.Panel1.Invalidate(); – Brandi 2010-06-24 19:51:18

+2

这不是一个好主意。 Windows窗体提供的缓冲区效率更高。 – 2010-06-24 20:11:24

相关问题