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容器,将程序的背景图片放到里面,再运行程序,程序背景闪烁的问题就完美解决了!

  • 相关阅读:
    【C++】资源管理
    【Shell脚本】逐行处理文本文件
    【算法题】rand5()产生rand7()
    【Shell脚本】字符串处理
    Apple iOS产品硬件参数. 不及格的程序员
    与iPhone的差距! 不及格的程序员
    iPhone游戏 Mr.Karoshi"过劳死"通关. 不及格的程序员
    XCode V4 发布了, 苹果的却是个变态. 不及格的程序员
    何时readonly 字段不是 readonly 的?结果出呼你想象!!! 不及格的程序员
    object file format unrecognized, invalid, or unsuitable Command 不及格的程序员
  • 原文地址:https://www.cnblogs.com/lihuali/p/10255582.html
Copyright © 2011-2022 走看看