Двойная буферизация с C # имеет отрицательный эффект - PullRequest
2 голосов
/ 02 апреля 2010

Я написал следующую простую программу, которая рисует линии на экране каждые 100 миллисекунд (запускается по таймеру1). Я заметил, что рисунок немного мерцает (то есть окно не всегда полностью голубое, но сквозь него просвечивает какой-то серый). Поэтому моя идея заключалась в использовании двойной буферизации. Но когда я это сделал, все стало еще хуже. Теперь экран был почти всегда серым, и только изредка появлялся синий цвет (продемонстрировано таймером 2, переключающим свойство 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 ]

5 голосов
/ 02 апреля 2010

Я бы просто перетянул все ваши вещи в ваш собственный буфер, а затем скопировал все сразу.Я использовал это для графики во многих приложениях, и он всегда работал очень хорошо для меня:

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

Таким образом, ваша проблема может быть решена путем создания ручного буфера, как я делал выше, или простого измененияВаш графический объект.Я проверил оба, и они оба работают.

2 голосов
/ 02 апреля 2010

Нет необходимости использовать несколько буферов, растровых объектов или чего-либо еще.

Почему вы не используете объект Graphics, предоставленный событием Paint? Как это:

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 голосов
/ 02 апреля 2010

Попробуйте установить свойство 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);
        }
    }
}

Это слегка взломанная версия примера двойной буферизации на MSDN .

...