zoukankan      html  css  js  c++  java
  • Winform应用程序中窗体背景闪烁的问题

    本文转载:https://my.oschina.net/Tsybius2014/blog/659742

    我的操作系统是Win7,使用的VS版本是VS2012,文中的代码都是C#代码。

    这几天遇到一个问题,即我用一个嵌入图片的Panel作为Winform应用程序的背景,如下图所示:

    这是一个Winform窗体,里面放置了一个Panel,Dock属性为Fill,BackgroundImage使用了《少年电世界》2003年第02期的封面图片,BackgroundImageLayout使用了Stretch。

    这个界面现在有两个问题:

    1、在窗体第一次被打开时,背景图片会出现明显的闪烁

    2、在拉动窗体的边界以调整窗体大小时,背景图片非出现明显的闪烁

    为了处理这一问题,我查了一些资料,也都逐个试过了,下面先说下其中的两个有代表性方法:

    方法1:直接使用双缓冲

    SetStyle(ControlStyles.UserPaint, true);
    SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
    SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲

    我尝试着将这段代码加到窗体的构造函数中,并不能解决问题,闪烁依然非常明显

    在MSDN上还有一篇文章《如何通过对窗体和控件使用双缓冲来减少图形闪烁》

    地址:https://msdn.microsoft.com/zh-cn/library/3t7htc9c%28v=vs.80%29.aspx

    这篇文章中也介绍了一个方法使用双缓冲:

    SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

    这个方法依然不能解决问题

    方法2:重写CreateParams方法

    方法2需要将以下这段代码放在Form类的代码内

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams paras = base.CreateParams;
            paras.ExStyle |= 0x02000000;
            return paras;
        }
    }

    这个方法我一开始尝试的时候一度认为是有效的,但使用了一段时间后还是发现了问题:

    1、这个方法可以解决问题1,但不能解决问题2

    2、这个方法会影响一些其他控件、组件的重绘(这点才是致命的)

    因此,这个方法也不能解决问题

    上面两个方法都不能解决问题,于是我继续求助度娘,终于在下面这个页面找到了解决方法:

    方法3:封装Panel类

    http://blog.chinaunix.net/uid-14414741-id-2814313.html

    这个方法,需要新建一个PanelEnhanced类继承Panel类,代码如下:

    /// <summary>
    /// 加强版 Panel
    /// </summary>
    class PanelEnhanced : Panel
    {
        /// <summary>
        /// OnPaintBackground 事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // 重载基类的背景擦除函数,
            // 解决窗口刷新,放大,图像闪烁
            return;
        }
    
        /// <summary>
        /// OnPaint 事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            // 使用双缓冲
            this.DoubleBuffered = true;
            // 背景重绘移动到此
            if (this.BackgroundImage != null)
            {
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                e.Graphics.DrawImage(
                    this.BackgroundImage,
                    new System.Drawing.Rectangle(0, 0, this.Width, this.Height),
                    0,
                    0,
                    this.BackgroundImage.Width,
                    this.BackgroundImage.Height,
                    System.Drawing.GraphicsUnit.Pixel);
            }
            base.OnPaint(e);
        }
    }

    将之前我们建立窗体中的Panel容器换为我们新封装的PanelEnhanced容器,将程序的背景图片放到里面,再运行程序,程序背景闪烁的问题就完美解决了!

  • 相关阅读:
    IE表单拦截器
    使用网站作为WCF服务宿主的几种做法
    Javascript执行效率小结
    Ajax无刷新技术实现省市县三级联动下拉菜单Asp.Net
    序列化DataContractSerializer
    变化多端的列表
    腾讯微信
    Mac OS 和 iOS 操作系统架构
    程序员远离你的细节思维
    ObjectiveC概述
  • 原文地址:https://www.cnblogs.com/lihuali/p/10255582.html
Copyright © 2011-2022 走看看