2010-04-02 3 views
2

Я написал следующую простую программу, которая рисует линии на экране каждые 100 миллисекунд (срабатывает по таймеру 1). Я заметил, что рисунок немного мерцает (то есть, окно не всегда полностью голубое, но серый светит). Поэтому моя идея заключалась в использовании двойной буферизации. Но когда я это сделал, это еще больше ухудшило ситуацию. Теперь экран почти всегда был серым, и только изредка шел синий цвет (демонстрируемый таймером2, переключая свойство DoubleBuffered каждые 2000 миллисекунд).Двойная буферизация с C# имеет отрицательный эффект

Что может быть для этого объяснением?

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

ответ

2

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

Почему вы не используете объект 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); 
} 
+0

Да, вы правы. Это было частью 2 моего ответа. –

+0

Это просто и работает. Благодарю. –

2

Попробуйте присвоить двойное буферное свойство 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.

+0

Я уже сделал это, с тем же эффектом. Периодическое переключение предназначено только для того, чтобы показать эффект более четко. –

5

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

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

EDIT: После дальнейших исследований, это выглядит как ваша проблема является то, что вы создаете свой графический объект чтобы:

Graphics g = CreateGraphics(); 

потребности быть:

Graphics g = e.Graphics(); 

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

Смежные вопросы