C# 双缓冲有负面影响

发布于 2024-08-27 15:49:09 字数 1084 浏览 4 评论 0原文

我编写了下面的简单程序,每 100 毫秒在屏幕上画一条线(由计时器 1 触发)。我注意到绘图有点闪烁(也就是说,窗口并不总是完全蓝色,而是透出一些灰色)。所以我的想法是使用双缓冲。但当我这样做时,事情变得更糟了。现在屏幕几乎总是灰色的,只有偶尔出现蓝色(由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";
        }
    }
}

I have written the following simple program, which draws lines on the screen every 100 milliseconds (triggered by timer1). I noticed that the drawing flickers a bit (that is, the window is not always completely blue, but some gray shines through). So my idea was to use double-buffering. But when I did that, it made things even worse. Now the screen was almost always gray, and only occasionally did the blue color come through (demonstrated by timer2, switching the DoubleBuffered property every 2000 milliseconds).

What could be an explanation for this?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生生不灭 2024-09-03 15:49:09

我会将所有项目绘制到您自己的缓冲区中,然后立即将其全部复制进去。我在许多应用程序中将其用于图形,并且它对我来说一直非常有效:

    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 对象来解决。我已经测试了两者并且它们都有效。

I would just draw all of your items to your own buffer, then copy it all in at once. I've used this for graphics in many applications, and it has always worked very well for me:

    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: After further investigation, it looks like your problem is what you're setting your Graphics object to:

Graphics g = CreateGraphics();

needs to be:

Graphics g = e.Graphics();

So your problem can be solved by either creating a manual buffer like I did above, or simply changing you Graphics object. I've tested both and they both work.

梦晓ヶ微光ヅ倾城 2024-09-03 15:49:09

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

为什么不使用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);
}

No need to use multiple buffers or Bitmap objects or anything.

Why don't you use the Graphics object provided by the Paint event? Like this:

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);
}
鸵鸟症 2024-09-03 15:49:09

测试时,尝试在构造函数中将双缓冲属性设置为 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 上。

Try setting the double buffered property to true just once in the constructor while you're testing.

You need to make use of the back buffer. Try this:

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

It's a slightly hacked around version of a double buffering example on MSDN.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文