【问题标题】:Paint Event e.Graphics.DrawImage doesn't seem to follow double bufferingPaint Event e.Graphics.DrawImage 似乎没有遵循双缓冲
【发布时间】:2021-01-15 14:49:33
【问题描述】:

目前正在重写旧代码,我正在使用图形函数根据位置数据绘制基于矢量的交互式地图。

回到使用 .NET 4.7 时,我可以简单地将我的东西绘制到位图中,执行 Graphics gr = Panel.CreateGraphics(),然后执行 gr.DrawImage()。我从来没有启用双缓冲,它总是工作得很好。

现在我在 .NET 5 中,仍然使用 WinForms,并尝试根据 Paint 事件做得更好一些,并在与之交互时使组件无效。

这是我的问题的核心

Bitmap Buffer; //this is initialized elsewhere, don't worry

public void MapPlotPanel_Paint(object sender, PaintEventArgs e)
{
//... Drawing code removed, it's just a novel Graphics object drawing into the Bitmap ...
e.Graphics.DrawImage(Buffer, Point.Empty);
}

虽然这可以很好地将图像绘制到面板中,但我得到了可怕的闪烁,因为我可以看到位图被实时绘制到面板中。即使我在事件处理程序中使用 Panel.CreateGraphics() 并使用它而不是 PaintEventArgs 对象,正如我之前所做的那样,也会发生同样的事情。

在表单加载事件处理程序中,我有

SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

没有效果。

不过,最糟糕的是,如果我不使用 Graphics 将图像应用到面板,而是使用 Panel.BackgroundImage = Buffer,它永远不会闪烁,但是当然,绘制的内容只会在下次组件出现时显示无效。

我真的想不出我在这里可能缺少什么,任何帮助将不胜感激。

【问题讨论】:

  • 不要在代码中的任何地方使用Control.CreateGraphics()。然后,使用双缓冲控件作为 PictureBox 或平面标签。不清楚为什么会有这个:MapPlotGraphics.DrawImage(Buffer, Point.Empty); 在控件的 Paint 事件中。您不应该将图像绘制到控件的 DC 上吗?这是什么方法?为什么你那里没有e.Graphics.DrawImage(Buffer, ...)? -- 从表单的构造函数中删除所有SetStyle() 的东西(Load 事件?)。
  • 啊,我的错,那是一个我忘记改回来的实验。我/不/在我的代码中的任何地方使用 Control.CreateGraphics(),我曾经,现在我正在重新实现它。我可以快速尝试一个 PictureBox,我一直在使用面板,所以也许这是出于某种原因。
  • 您需要为绘图画布而不是表单执行此操作SetStyle(ControlStyles.OptimizedDoubleBuffer, true);。你的情况下的小组。子类化并启用它,或者只使用一个 PictureBox,默认情况下是双缓冲的。
  • 面板不是双缓冲的。您将这些用于绘画,使用OptimizedDoubleBuffer 功能,以获得一些特殊效果(图形的温和持久性)。你可以在这里看到一个:Transparent Overlapping Circular Progress Bars (Custom Control):使用标准 BufferedGraphics 的控件不会得到相同的结果。 -- 贴出真实代码。 (顺便说一句,SetStyle() 是从控件的 构造函数 调用的,而不是 Load 事件)
  • 对于绘图,我推荐 PBox 或 (!) Label。两者都是开箱即用的双缓冲。 Label是比较简单的控件,PBox除了surface之外还有Imge和BackgroundImage。面板是一个容器,不适合在上面画画。..

标签: c# winforms .net-5


【解决方案1】:

正如 cmets 中已经提到的 - 要启用面板的双缓冲,您需要在面板构造函数中 SetStyle(),而不是在表单加载事件中。为此,您必须创建自己的面板。下面是自定义面板类的示例代码。

public partial class CustomPanel : UserControl
{
    public CustomPanel()
    {
        InitializeComponent();

        // Add Double Buffering
        SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 2016-11-07
    相关资源
    最近更新 更多