问题背景
在工控项目中, 往往需要加载一个背景图像用于模拟设备或图纸, 在其上需要动态放置一些标签或按钮,
通常的做法是, 使用Panel组件通过设置 BackgroundImage 属性加载背景图, 经常碰到的问题是, 窗口做resize或动态增加/删除Label时, 界面会有非常明显的屏闪现象.
public void loadPicture(string fileName)
{
pnlContainer.BackgroundImageLayout = ImageLayout.Stretch;
pnlContainer.BackgroundImage = null;
if (string.IsNullOrWhiteSpace(fileName) == false)
{
pnlContainer.BackgroundImage = Image.FromFile(fileName);
}
}
方案: 使用 pictureBox 加载背景图
在容器panel中新增一个 pictureBox 组件, 使用 pictureBox 组件来加载背景图像, pictureBox 组件本身做过优化, 能很好的解决屏闪问题. 唯一问题是 pictureBox 组件不能作为容器, 动态生成的 label 组件的 z-order 方向, 总是被 pictureBox 覆盖住, 所以在动态生成 label 后, pictureBox1.SendToBack(), 确保 pictureBox1 放置到最下层.
public void loadPicture(string fileName)
{
pictureBox1.BackgroundImageLayout = ImageLayout.Stretch;
pictureBox1.BackgroundImage = null;
if (string.IsNullOrWhiteSpace(fileName) == false)
{
pictureBox1.BackgroundImage = Image.FromFile(fileName);
}
}
//在调用 newManyLabels() 之后, 再调用 pictureBox1.SendToBack(), 确保 pictureBox1 放置到最下层, 形成背景效果.
方案: 使用 timer 降低 repaint 频次
窗口大小变化时,不立即刷新panel。可以使用Timer延迟刷新,比如50毫秒。这样可以合并多个大小调整导致的刷新请求,避免过度绘制和闪烁。
Timer timer = new Timer();
timer.Interval = 50;
timer.Tick += (s, e) => panel.Invalidate();
方案: 使用双缓存技术
在我的场景中没什么效果:
http://csharp.tips/tip/article/852-how-to-prevent-flicker-in-winforms-control
https://chuxing.blog.csdn.net/article/details/38313575