【发布时间】: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。面板是一个容器,不适合在上面画画。..