2010-06-24 49 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

相關問題