C#使用双缓冲绘图

刚开始学C#绘图时候做用户控件,直接在屏幕的Graphics画笔绘图,频繁刷新画布就明显肉眼可见抖动。那时候研究怎么减少绘图刷新的抖动,就接触到双缓存绘图概念。

源码地址

什么是双缓冲绘图呢?就是如果画笔直接在屏幕画板操作的话,每次绘制都会刷新屏幕,就会很抖动。双缓冲的方法是建立一个屏幕大小的bitmap,先画笔在bitmap上画完之后。再把整个画完的图画到屏幕画板,就极大的减少屏幕刷新,就减少抖动。

我以前找的介绍资料:
在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。
因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪烁。以上也就是双缓冲绘图的基本的思路。

肉眼看的到明显差别,截图竟然截不到。
C#使用双缓冲绘图_第1张图片

用双缓冲和不用双缓冲的代码示例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Drawing2D;

namespace DoubleCushionDraw
{
    public partial class Form1 : Form
    {
        int ss = 0;
        public Form1()
        {
            InitializeComponent();
            //Draw();

        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            //Draw();
            //Pen pen = new Pen(Color.Red);
            //pen.Width = 1.0F;
            //e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 370, i, 50, 50);

            //String drawString = "Sample Text";

             Create font and brush.
            //Font drawFont = new Font("Arial", 16);
            //SolidBrush drawBrush = new SolidBrush(Color.Yellow);

             Create rectangle for drawing.
            //float x = 150.0F;
            //float y = 150.0F+i;
            //float width = 200.0F;
            //float height = 50.0F;
            //RectangleF drawRect = new RectangleF(x, y, width, height);

             Draw rectangle to screen.
            //Pen blackPen = new Pen(Color.Yellow);
            //e.Graphics.DrawRectangle(blackPen, x, y, width, height);

             Set format of string.
            //StringFormat drawFormat = new StringFormat();
            //drawFormat.Alignment = StringAlignment.Center;

             Draw string to screen.
            //e.Graphics.DrawString(drawString, drawFont, drawBrush, drawRect, drawFormat);

            //timer1.Enabled = true;

            //-----------------------------------------------------
            //Rectangle rect = e.ClipRectangle;
            //BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
            //BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
            //Graphics g = myBuffer.Graphics;
            //g.SmoothingMode = SmoothingMode.HighQuality;
            //g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            g.Clear(this.BackColor);
            //Pen pen = new Pen(Color.Red);
            //pen.Width = 1.0F;

            //e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 370, i, 50, 50);
            foreach (Shape shape in Server.ShapeList)
            {
                if (rect.IntersectsWith(drawobject.Rect))
                {
                    drawobject.Draw(g);
                    if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
                        && this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
                    {
                        drawobject.DrawTracker(g);
                    }
                }
            }
            //myBuffer.Render(e.Graphics);
            //g.Dispose();
            //myBuffer.Dispose();//释放资源

            //timer1.Enabled = true;

            //---------------------------------------------

            //Graphics g = e.Graphics;
            //Pen bluePen = new Pen(Color.Blue);
            //Bitmap localBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
            //Graphics bitmapGraphics = Graphics.FromImage(localBitmap);
            //LineDrawRoutine(bitmapGraphics, bluePen);
            //bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;

            //g.DrawImage(localBitmap, 0, 0);

            //bitmapGraphics.Dispose();

            //bluePen.Dispose();
            //localBitmap.Dispose();
            //g.Dispose();

            //timer1.Enabled = true;
        }
        bool flag = true;
        bool flag1 = true;
        bool a = false;
        private void Draw()
        {
            if (a)
            {
                this.Refresh();
            }
            SolidBrush myBrush = new SolidBrush(this.BackColor );
            //优化前
            DateTime t1 = DateTime.Now;
            Graphics g = this.CreateGraphics();
            g.FillRectangle(myBrush ,new Rectangle (0,0,600,600));
            LinearGradientBrush brush;
            if (flag)
            {
                brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),
                    new PointF(700.0f, 300.0f), Color.Red, Color.Blue);
                flag = false;
            }
            else
            {
                brush = new LinearGradientBrush(new PointF(0.0f, 0.0f),
                    new PointF(700.0f, 300.0f), Color.Blue, Color.Red);
                flag = true;
            }
            for (int j = 0; j < 60; j++)
            {
                for (int i = 0; i < 60; i++)
                {
                    g.FillEllipse(brush, i * 10, j * 10, 10, 10);
                }
            }
            Pen pen = new Pen(Color.Lime);
            pen.Width = 2.0F;
            g.DrawRectangle(pen, 1, ss, 50, 50);
            g.DrawRectangle(pen, 60, ss, 50, 50);
            g.DrawRectangle(pen, 120, ss, 50, 50);
            g.DrawRectangle(pen, 170, ss, 50, 50);
            g.DrawRectangle(pen, 220, ss, 50, 50);
            g.DrawRectangle(pen, 270, ss, 50, 50);
            g.DrawRectangle(pen, 320, ss, 50, 50);
            g.DrawRectangle(pen, 370, ss, 50, 50);

           

            //优化后
            //DateTime t1 = DateTime.Now;
            Bitmap bmp = new Bitmap(600, 600);
            Graphics g1 = Graphics.FromImage(bmp);
            g1.Clear(this.BackColor);
            LinearGradientBrush brush1;
            if (flag1)
            {
                brush1 = new LinearGradientBrush(new PointF(0.0f, 0.0f),
                        new PointF(700.0f, 300.0f), Color.Red, Color.Blue);
                flag1 = false;
            }
            else
            {
                brush1 = new LinearGradientBrush(new PointF(0.0f, 0.0f),
                        new PointF(700.0f, 300.0f), Color.Blue, Color.Red);
                flag1 = true;
            }
            for (int j = 0; j < 60; j++)
            {
                for (int i = 0; i < 60; i++)
                {
                    g1.FillEllipse(brush1, i * 10, j * 10, 10, 10);
                }
            }

           
            g1.DrawRectangle(pen, 1, ss, 50, 50);
            g1.DrawRectangle(pen, 60, ss, 50, 50);
            g1.DrawRectangle(pen, 120, ss, 50, 50);
            g1.DrawRectangle(pen, 170, ss, 50, 50);
            g1.DrawRectangle(pen, 220, ss, 50, 50);
            g1.DrawRectangle(pen, 270, ss, 50, 50);
            g1.DrawRectangle(pen, 320, ss, 50, 50);
            g1.DrawRectangle(pen, 370, ss, 50, 50);

            this.CreateGraphics().DrawImage(bmp, 650, 0);
            
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            ss = ss + 1;
            if (checkBox1.CheckState == CheckState.Checked)
            {
                a = true;
            }
            else
            {
                a = false;
            }
           // this.Invalidate();
            try
            {
                timer1.Interval = Convert.ToInt32(textBox1.Text);
            }
            catch (Exception)
            {
              
            }
            Draw();
           
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            //Pen pen = new Pen(Color.Red);
            //pen.Width = 1.0F;
            //e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 370, i, 50, 50);

            //String drawString = "Sample Text";

             Create font and brush.
            //Font drawFont = new Font("Arial", 16);
            //SolidBrush drawBrush = new SolidBrush(Color.Yellow);

             Create rectangle for drawing.
            //float x = 150.0F;
            //float y = 150.0F+i;
            //float width = 200.0F;
            //float height = 50.0F;
            //RectangleF drawRect = new RectangleF(x, y, width, height);

             Draw rectangle to screen.
            //Pen blackPen = new Pen(Color.Yellow);
            //e.Graphics.DrawRectangle(blackPen, x, y, width, height);

             Set format of string.
            //StringFormat drawFormat = new StringFormat();
            //drawFormat.Alignment = StringAlignment.Center;

             Draw string to screen.
            //e.Graphics.DrawString(drawString, drawFont, drawBrush, drawRect, drawFormat);

            //timer1.Enabled = true;

           //-----------------------------------------------------
            //Rectangle rect = e.ClipRectangle;
            //BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
            //BufferedGraphics myBuffer = currentContext.Allocate(e.Graphics, e.ClipRectangle);
            //Graphics g = myBuffer.Graphics;
            //g.SmoothingMode = SmoothingMode.HighQuality;
            //g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            g.Clear(this.BackColor);
            //Pen pen = new Pen(Color.Red);
            //pen.Width = 1.0F;

            //e.Graphics.DrawRectangle(pen, 1, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 60, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 120, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 170, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 220, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 270, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 320, i, 50, 50);
            //e.Graphics.DrawRectangle(pen, 370, i, 50, 50);
            foreach (Shape shape in Server.ShapeList)
            {
                if (rect.IntersectsWith(drawobject.Rect))
                {
                    drawobject.Draw(g);
                    if (drawobject.TrackerState == config.Module.Core.TrackerState.Selected
                        && this.CurrentOperator == Enum.Operator.Transfrom)//仅当编辑节点操作时显示图元热点
                    {
                        drawobject.DrawTracker(g);
                    }
                }
            }
            //myBuffer.Render(e.Graphics);
            //g.Dispose();
            //myBuffer.Dispose();//释放资源

            //timer1.Enabled = true;

           //---------------------------------------------

            //Graphics g = e.Graphics;
            //Pen bluePen = new Pen(Color.Blue);
            //Bitmap localBitmap = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
            //Graphics bitmapGraphics = Graphics.FromImage(localBitmap);
            //LineDrawRoutine(bitmapGraphics, bluePen);
            //bitmapGraphics.SmoothingMode = SmoothingMode.AntiAlias;

            //g.DrawImage(localBitmap, 0, 0);

            //bitmapGraphics.Dispose();

            //bluePen.Dispose();
            //localBitmap.Dispose();
            //g.Dispose();

            //timer1.Enabled = true;
        }

        private void LineDrawRoutine(Graphics g, Pen p)
        {
            //float width = ClientRectangle.Width;
            //float height = ClientRectangle.Height;
            //float xDelta = width / 20;
            //float yDelta = height / 20;

            //for (int j = 0; j < 20; j++)
            //{
            //    g.DrawLine(p, 0, height - (yDelta * j)+i, xDelta * j, 0);
            //}

            //g.DrawRectangle(p, 1, i, 50, 50);
            //g.DrawRectangle(p, 60, i, 50, 50);
            //g.DrawRectangle(p, 120, i, 50, 50);
            //g.DrawRectangle(p, 170, i, 50, 50);
            //g.DrawRectangle(p, 220, i, 50, 50);
            //g.DrawRectangle(p, 270, i, 50, 50);
            //g.DrawRectangle(p, 320, i, 50, 50);
            //g.DrawRectangle(p, 370, i, 50, 50);
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            //this.Invalidate();
          // Draw();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            //Draw();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Draw();
            this.Invalidate();
        }

    }
}

你可能感兴趣的:(C#,c#,ui,开发语言)