【问题标题】:Double buffering with C# has negative effect使用 C# 进行双缓冲有负面影响
【发布时间】:2010-04-02 10:21:25
【问题描述】:

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

对此有何解释?

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";
        }
    }
}

【问题讨论】:

    标签: c# winforms graphics doublebuffered


    【解决方案1】:

    我只是将你所有的项目都绘制到你自己的缓冲区中,然后一次将它们全部复制进去。我在许多应用程序中都将它用于图形,它对我来说一直很有效:

        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 对象设置为:

    Graphics g = CreateGraphics();
    

    需要:

    Graphics g = e.Graphics();
    

    所以你的问题可以通过像我上面做的那样创建一个手动缓冲区来解决,或者只是改变你的 Graphics 对象。我都测试过了,它们都可以工作。

    【讨论】:

      【解决方案2】:

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

      为什么不使用 Paint 事件提供的 Graphics 对象呢?像这样:

      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);
      }
      

      【讨论】:

        【解决方案3】:

        在测试时尝试在构造函数中将双缓冲属性设置为 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 的一个稍微修改过的版本。

        【讨论】:

        • 我已经这样做了,效果相同。周期性切换只是为了更清楚地显示效果。
        猜你喜欢
        • 2011-02-20
        • 2010-10-09
        • 1970-01-01
        • 1970-01-01
        • 2013-10-20
        • 1970-01-01
        • 2011-03-05
        • 2011-10-16
        • 2010-10-19
        相关资源
        最近更新 更多