【问题标题】:Problems re-drawing an image on a double-buffered control without flickering在双缓冲控件上重新绘制图像而不闪烁的问题
【发布时间】:2010-10-05 10:58:52
【问题描述】:

我知道双缓冲是一个经常被谈论的话题,但无论我如何搜索和尝试不同的方法,我仍然无法让控件在没有闪烁的情况下重新绘制自身。这是我的代码:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Emgu.UI
{
    public class DoubleBufferedPictureBox : Control
    {
        const BufferedGraphics NO_MANAGED_BACK_BUFFER = null;

        BufferedGraphicsContext GraphicManager;
        BufferedGraphics ManagedBackBuffer;

        public Bitmap Bitmap { get; set; }
        public Rectangle DrawRectangle { get; set; }

        public DoubleBufferedPictureBox()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);

            GraphicManager = BufferedGraphicsManager.Current;
            GraphicManager.MaximumBuffer =
                   new Size(Width + 1, Height + 1);
            ManagedBackBuffer =
                GraphicManager.Allocate(CreateGraphics(),
                                               ClientRectangle);

            Resize += DoubleBufferedPictureBox_Resize;
        }

        void DoubleBufferedPictureBox_Resize(object sender, EventArgs e)
        {
            if (ManagedBackBuffer != NO_MANAGED_BACK_BUFFER)
                ManagedBackBuffer.Dispose();

            GraphicManager.MaximumBuffer =
                  new Size(Width + 1, Height + 1);

            ManagedBackBuffer =
                GraphicManager.Allocate(CreateGraphics(),
                                                ClientRectangle);
            Refresh();
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            ManagedBackBuffer.Graphics.DrawImage(Bitmap, DrawRectangle);
            ManagedBackBuffer.Render(pe.Graphics);
        }

    }
}

有什么想法吗?

【问题讨论】:

  • 如果您设置 OptimizedDoubleBuffer 标志,您还必须设置 UserDraw 标志。你试过吗?

标签: c# drawing doublebuffered


【解决方案1】:

天哪……

就像我在 cmets 中所说的那样,pictureBox 包含在另一个我没有编写的控件中(但有源代码)。原来闪烁是由这两行引起的:

if (pictureBox.Width != _displayedImage.Width) pictureBox.Width = _displayedImage.Width;
if (pictureBox.Height != _displayedImage.Height) pictureBox.Height = _displayedImage.Height;

我认为那是因为 PictureBox 实际上是停靠在父控件中的...

无论如何,感谢您的所有回复。

【讨论】:

  • 你可能想同时做这两个 - 即pictureBox.Size = _displayedImage.Size。
【解决方案2】:

您使用的是 .Net 2.0 吗?如果是这样,我发现以下 windows 样式可以解决问题,即使嵌入了旧的顽固 Win32 控件,而且速度也很快!

// Note the >>> Optimized <<< DoubleBuffer
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);

确保您始终从 WM_PAINT 消息内部绘图,否则它会闪烁。 您不需要其他任何东西,一切都是自动的。

【讨论】:

    【解决方案3】:

    您是否尝试将控件DoubleBuffered 属性设置为true?

    【讨论】:

    • 你的 SetStyles 方法怎么样?例如:SetStyles(ControlStyles.AllPaintingInWmPaint | ControlSyles.DoubleBuffer, true);
    • ControlStyles.DoubleBuffer 来自 1.1 - 我使用了 2.0 的 OptimizedDoubleBuffer 没有效果...
    • 那么...您确定要渲染缓冲区然后复制图形吗?看起来您可能只是使用缓冲区直接渲染到 Graphics 属性,而不是缓冲渲染图形然后将其复制过来。
    • 我什至尝试过手动执行此操作。也就是说 - 我创建了一个 32-bpp 位图,它是具有 DoubleBuffered = true 的 PictureBox 的 ClientSize,然后将其设置为 PictureBox.Image - 它仍然闪烁它......
    • 如果您设置 OptimizedDoubleBuffer 标志,您还必须设置 UserDraw 标志。你试过吗?
    【解决方案4】:

    父控件(窗体?)中的绘画是否也是双缓冲的?

    您的自定义控件可能会在没有闪烁的情况下绘制,但是当父控件被绘制并且没有双缓冲时,它会闪烁。

    你可能在双重缓冲错误的东西。

    【讨论】:

    • 你能把你正在尝试的代码上传到某个地方,以便我们修改它吗?
    • 嗯 - 我正在尝试重新制作它,但事实证明这很困难 - PictureBox 包含在另一个我没有自己设计的控件中,这就是闪烁似乎来自的地方 - 我'我现在调查更多。
    【解决方案5】:

    我认为问题在于您的 OnPaint 方法 from MSDN,当您调用 ManagedBackBuffer.Render 方法时,您应该传递 CreateGraphics() 而不是 Graphics 属性:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-17
      • 2014-08-13
      • 1970-01-01
      • 1970-01-01
      • 2012-06-07
      • 2014-10-12
      • 2015-05-01
      • 1970-01-01
      相关资源
      最近更新 更多