我编写了以下简单程序,它每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";
}
}
}
答案 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;
}
编辑:经过进一步调查后,您的问题就是您将Graphics对象设置为:
Graphics g = CreateGraphics();
需要:
Graphics g = e.Graphics();
因此,您可以通过创建像我上面所做的手动缓冲区或者只是更改Graphics对象来解决您的问题。我已经测试了两者,它们都有效。
答案 1 :(得分:2)
在测试时,尝试在构造函数中将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的一个有点被黑客攻击的版本。
答案 2 :(得分:2)
无需使用多个缓冲区或Bitmap对象或任何东西。
为什么不使用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);
}