代码之家  ›  专栏  ›  技术社区  ›  Roland Illig

带C的双缓冲具有负面影响

  •  2
  • Roland Illig  · 技术社区  · 15 年前

    我编写了下面的简单程序,它每100毫秒在屏幕上绘制一行(由timer1触发)。我注意到这幅画有点闪烁(也就是说,窗户并不总是完全是蓝色的,但有一些灰色的光线穿透)。所以我的想法是使用双缓冲。但当我这样做的时候,事情变得更糟了。现在屏幕几乎总是灰色的,只有偶尔出现蓝色(由Timer2显示,切换 DoubleBuffered 属性每隔2000毫秒)。

    对此有什么解释?

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1 {
        public partial class Form1 : Form {
            public Form1() {
                InitializeComponent();
            }
    
            private void Form1_Paint(object sender, PaintEventArgs e) {
                Graphics g = CreateGraphics();
                Pen pen = new Pen(Color.Blue, 1.0f);
                Random rnd = new Random();
                for (int i = 0; i < Height; i++)
                    g.DrawLine(pen, 0, i, Width, i);
            }
    
            // every 100 ms
            private void timer1_Tick(object sender, EventArgs e) {
                Invalidate();
            }
    
            // every 2000 ms
            private void timer2_Tick(object sender, EventArgs e) {
                DoubleBuffered = !DoubleBuffered;
                this.Text = DoubleBuffered ? "yes" : "no";
            }
        }
    }
    
    3 回复  |  直到 15 年前
        1
  •  2
  •   Daniel A.A. Pelsmaeker    15 年前

    不需要使用多个缓冲区或位图对象或任何东西。

    为什么不使用绘制事件提供的图形对象?这样地:

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        Pen pen = new Pen(Color.Blue, 1.0f);
        Random rnd = new Random();
        for (int i = 0; i < Height; i++)
            g.DrawLine(pen, 0, i, Width, i);
    }
    
        2
  •  5
  •   Seth Moore    15 年前

    我只需要把你所有的项目都放到你自己的缓冲区,然后一次把它们全部复制进去。我在许多应用程序中都使用过这种方法,而且它对我来说一直都非常有效:

        public Form1()
        {
            InitializeComponent();
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            Invalidate();// every 100 ms
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            DoubleBuffered = true;
        }
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Bitmap buffer = new Bitmap(Width, Height);
            Graphics g = Graphics.FromImage(buffer);
            Pen pen = new Pen(Color.Blue, 1.0f);
            //Random rnd = new Random();
            for (int i = 0; i < Height; i++)
                g.DrawLine(pen, 0, i, Width, i);
            BackgroundImage = buffer;
        }
    

    编辑: 进一步调查后,您的问题似乎是您要将图形对象设置为:

    Graphics g = CreateGraphics();
    

    需要:

    Graphics g = e.Graphics();
    

    所以你的问题可以通过创建一个手动缓冲区来解决,就像我上面所做的那样,或者简单地改变你的图形对象。我已经测试过了,它们都能工作。

        3
  •  2
  •   Jon Cage    15 年前

    在测试时,尝试在构造函数中将Double Buffered属性设置为true一次。

    你需要利用后缓冲区。试试这个:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace DoubleBufferTest
    {
        public partial class Form1 : Form
        {
            private BufferedGraphicsContext context;
            private BufferedGraphics grafx;
    
            public Form1()
            {
                InitializeComponent();
    
                this.Resize += new EventHandler(this.OnResize);
                DoubleBuffered = true;
    
                // Retrieves the BufferedGraphicsContext for the 
                // current application domain.
                context = BufferedGraphicsManager.Current;
    
                UpdateBuffer();
            }
    
            private void timer1_Tick(object sender, EventArgs e)
            {
                this.Refresh();
    
            }
    
            private void OnResize(object sender, EventArgs e)
            {
                UpdateBuffer();
                this.Refresh();
            }
    
            private void UpdateBuffer()
            {
                // Sets the maximum size for the primary graphics buffer
                // of the buffered graphics context for the application
                // domain.  Any allocation requests for a buffer larger 
                // than this will create a temporary buffered graphics 
                // context to host the graphics buffer.
                context.MaximumBuffer = new Size(this.Width + 1, this.Height + 1);
    
                // Allocates a graphics buffer the size of this form
                // using the pixel format of the Graphics created by 
                // the Form.CreateGraphics() method, which returns a 
                // Graphics object that matches the pixel format of the form.
                grafx = context.Allocate(this.CreateGraphics(),
                     new Rectangle(0, 0, this.Width, this.Height));
    
                // Draw the first frame to the buffer.
                DrawToBuffer(grafx.Graphics);
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                grafx.Render(e.Graphics);
            }
    
            private void DrawToBuffer(Graphics g)
            {
                //Graphics g = grafx.Graphics;
                Pen pen = new Pen(Color.Blue, 1.0f);
                //Random rnd = new Random();
                for (int i = 0; i < Height; i++)
                    g.DrawLine(pen, 0, i, Width, i);
            }
        }
    }
    

    这是一个稍微被黑客攻击的版本 a double buffering example on MSDN .