Graphics g = Graphics.FromImage(bufferimage);
g.SmoothingMode = SmoothingMode.HighQuality; //高質量
g.PixelOffsetMode = PixelOffsetMode.HighQuality; //高像素偏移質量
{
{
drawobject.Draw(g);
if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
&& this.CurrentOperator == Enum.Operator.Transfrom)//僅當編輯節點操作時顯示圖元熱點
{
drawobject.DrawTracker(g);
}
}
}
{
tg.DrawImage(bufferimage, 0, 0); //把畫布貼到畫面上
}
BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
Graphics g = myBuffer.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
g.Clear(this.BackColor);
foreach (IShape drawobject in doc.drawObjectList)
{
if (rect.IntersectsWith(drawobject.Rect))
{
drawobject.Draw(g);
if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
&& this.CurrentOperator == Enum.Operator.Transfrom)//僅當編輯節點操作時顯示圖元熱點
{
drawobject.DrawTracker(g);
}
}
}
g.Dispose();
myBuffer.Dispose();//釋放資源
或者:
Bitmap bmp = new Bitmap(600, 600);
2、獲取這塊內存畫布的Graphics引用:
Graphics g = Graphics.FromImage(bmp);
3、在這塊內存畫布上繪圖:
g.FillEllipse(brush, i * 10, j * 10, 10, 10);
4、將內存畫布畫到窗口中
this.CreateGraphics().DrawImage(bmp, 0, 0);
還有的方式
在構造函數中加如下代碼
代碼一:
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 雙緩沖
代碼二:
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();
=============================================================================================
使用 GDI+ 雙緩沖 解決繪圖閃爍問題
現在的問題是很多人不知道怎么怎么使用GDI+ 雙緩沖
public partial class Form1 : Form
{
//記錄矩形位置的變量
Point p = Point .Empty ;
Point location = new Point(0, 0);
int x = 0;
int y = 0;
public Form1()
{
InitializeComponent();
//采用雙緩沖技術的控件必需的設置
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.FillRectangle(Brushes.Black, x, y, 200, 200);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right) return;
p = e.Location;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right) return;
location.X += e.X - p.X;
location.Y += e.Y - p.Y;
p = Point.Empty;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (p == Point.Empty) return;
x = e.X - p.X + location.X;
y = e.Y - p.Y + location.Y;
this.Invalidate(true);//觸發Paint事件
}
}
這個簡單的例子實現了用鼠標拖動窗口中矩形,利用雙緩沖技術使動畫過程不會產生閃爍.
在這個例子上我犯的錯誤:
在 OnPaint(PaintEventArgs e)中,我使用下面兩種方法獲取graphics 對象
Graphics g = this.CreateGraphics();
Graphics g = Graphics.FromHwnd(this.Handle);
這都使雙緩沖失效.
獲得graphics 對象還有兩種方法是
Graphics g = Graphics.FromImage(image); //后面將用此方法實現雙緩沖
Graphics g = e.Graphics; //這是唯一好使的方法
上面是在Form窗口直接繪制圖形,那么如何在控件上(比如Panel)利用雙緩沖技術繪圖呢?
在窗口窗創建一個Panel , 並修改一下代碼
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.FillRectangle(Brushes.Black, x, y, 200, 200);
}
運行后發現拖動在panel1上繪制的圖形依然有閃爍,那么是不是應該這樣設置
panel1.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);//這樣並不行,
因為SetStyle()在Panel類中不是public方法
使用從Panel類繼承的MyPanel類 的構造函數中設置雙緩沖
public class MyPanel:Panel
{
public MyPanel()
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
}
}
不管怎么說這個方法的確好用,不過注意以后你使用的是MyPanel類,而不是Panel.
把自己定義MyPanel從工具欄里拖到窗口上和Panle一樣使用.
注意:在控件上繪制就必須設置該控件的DoubleBuffer,而不是Form的DoubleBuffer.
在此之前我采用自己的方法實現雙緩沖而不是控件自身的DoubleBuffer
先在內存里繪制圖形,包括清除舊畫面和繪制新畫面,然后將內存的圖形繪制到屏幕上
public void Draw(System.Windows.Forms.Panel _panel, float _x, float _y)
{
Graphics g = Graphics.FromHwnd(_panel.Handle);
try{
//在內存創建一塊和panel一大小的區域
Bitmap bitmap = new Bitmap(_panel.ClientSize.Width, _panel.ClientSize.Height);
using (Graphics buffer = Graphics.FromImage(bitmap))
{
//buffer中繪圖
buffer.Clear(_panel.BackColor); //用背景色填充畫面
buffer.Transform = matrix;
buffer.DrawImage(source, _x/Scale , _y/Scale ); //繪制新畫面
//屏幕繪圖
g.DrawImage(bitmap, 0, 0); //將buffer繪制到屏幕上
}
}
finally
{
g.Dispose();
}
}
使用上面方法不需要任何設置.
總結一下
與繪圖有關的ControlStyles
enum ControlStyles{
AllPainingInWmPaint, //將繪制階段折疊入Paint事件
DoubleBuffer, //直到Paint返回,再顯示繪制對象
UserPaint, //用於自身有着特別繪制的控件
Opaque, //忽略OnPaintBackground,Paint事件繪制整個區域
ResizeRedraw,//當調整控件大小時使整個工作區無效
SupportsTransparentBackColor,//模擬透明控件
...
}
1.在OnPaint(PaintEventArgs e)或Paint中 使用e獲取graphics,我之所以費了很大周折就是因為在網上找到一篇實現雙緩沖文章介紹,不要使用e獲取graphics,而用this.CreateGraphics(),還有的文章介紹了奇怪的方法居然最終也好使.
2.在繼承了Form和control 的控件上利用雙緩沖繪制的時候,可以在控件的構造函數里設置雙緩沖屬性,而在窗口Form 里設置doublebuffer,只針對窗口的繪制起作用.
3.使用自己的方法,雙緩沖的原理都是一樣的.
示例:
private void DrawRectBackImage()
{
Graphics g = Graphics.FromHwnd(_currentChart.Handle);
try
{
//在內存創建一塊和panel一大小的區域
Bitmap bitmap = new Bitmap(_currentChart.ClientSize.Width, _currentChart.ClientSize.Height);
using (Graphics buffer = Graphics.FromImage(bitmap))
{
buffer.Transform =new Matrix();
//要畫的背景圖片
buffer.DrawImage(curChartImage, _currentChart.ClientRectangle);
//背景圖片上的內容
DrawFitAdjustRect(buffer);
//屏幕繪圖
g.DrawImage(bitmap, 0, 0); //將buffer繪制到屏幕上
}
}
finally
{
g.Dispose();
}
}