zoukankan      html  css  js  c++  java
  • Winform应用程序实现通用遮罩层

    Winform应用程序实现通用遮罩层

     

    在WEB上,我们在需要进行大数据或复杂逻辑处理时,由于耗时较长,一般我们会在处理过程中的页面上显示一个半透明的遮罩层,上面放个图标或提示:正在处理中...等字样,这样用户体验就比较好了,然而如果在Winform客户端程序,通常遮罩层的处理就显得不那么简单或不那么好看,而我今天要说明的是,我实现的这个Winform通用遮罩层,却可以实现类似WEB上的遮罩层,既可以透明,而且还可以显示动态图片以及文字,那如何实现的呢,我现在一一讲解。

    首先要明确我们要实现的效果:透明+动态图标+文字

    透明:这个简单,只需要将窗体的Opacity设为100%以下的值就可以了,这里我采用85%;

    动态图标:这个相对复杂一些,因为Winform目前没有现成的支持直接显示动图的控件,但幸好有一个组件ImageAnimator支持逐帧动画,我们只需要将图片绑定到ImageAnimator的Animate方法上(即:ImageAnimator.Animate(m_Image,EventHandler委托);),然后重写窗体的OnPaint即可,具体的代码实现见下面公布的源码。

    文字:这个简单,放在一个Label控件即可

    还有为了能够让图标与文字在相对的位置(即不论大小)保持居中,我这里采用了一个TableLayoutPanel,分成两行,上行放置Label,并设为居中,下行放置Panel,提供绘制动图的区域。

    完整代码实现如下(部份代码参考网络上它人的文章):

    复制代码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Reflection;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace TEMS
    {
        public partial class FrmProcessing : Form
        {
            private static Image m_Image = null;
    
            private EventHandler evtHandler = null;
    
            private ParameterizedThreadStart workAction = null;
            private object workActionArg = null;
    
            private Thread workThread = null;
    
            public string Message
            {
                get
                {
                    return lbMessage.Text;
                }
                set
                {
                    lbMessage.Text = value;
                }
            }
    
            public bool WorkCompleted = false;
    
            public Exception WorkException
            { get; private set; }
    
            public void SetWorkAction(ParameterizedThreadStart workAction, object arg)
            {
                this.workAction = workAction;
                this.workActionArg = arg;
            }
    
            public FrmProcessing(string msg)
            {
                InitializeComponent();
                this.Message = msg;
            }
    
            protected override  void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
    
                if (m_Image != null)
                {
                    //获得当前gif动画下一步要渲染的帧。
                    UpdateImage();
    
                    //将获得的当前gif动画需要渲染的帧显示在界面上的某个位置。
                    int x = (int)(panImage.ClientRectangle.Width - m_Image.Width) / 2;
                    int y = 0;
                    //e.Graphics.DrawImage(m_Image, new Rectangle(x, y, m_Image.Width, m_Image.Height));
                    panImage.CreateGraphics().DrawImage(m_Image, new Rectangle(x, y, m_Image.Width, m_Image.Height));
                }
                if (this.WorkCompleted)
                {
                    this.Close();
                }
            }
    
    
            private void FrmProcessing_Load(object sender, EventArgs e)
            {
                if (this.Owner != null)
                {
                    this.StartPosition = FormStartPosition.Manual;
                    this.Location = new Point(this.Owner.Left, this.Owner.Top);
                    //MessageBox.Show(string.Format("X={0},Y={1}", this.Owner.Left, this.Owner.Top));
                    this.Width = this.Owner.Width;
                    this.Height = this.Owner.Height;
                }
                else
                {
                    Rectangle screenRect = Screen.PrimaryScreen.WorkingArea;
                    this.Location = new Point((screenRect.Width - this.Width) / 2, (screenRect.Height - this.Height) / 2);
                }
    
                //为委托关联一个处理方法
                evtHandler = new EventHandler(OnImageAnimate);
    
                if (m_Image == null)
                {
                    Assembly assy = Assembly.GetExecutingAssembly();
                    //获取要加载的gif动画文件
                    m_Image = Image.FromStream(assy.GetManifestResourceStream(assy.GetName().Name + ".Resources.loading2.gif"));
                }
                //调用开始动画方法
                BeginAnimate();
            }
    
    
            //开始动画方法
    
            private void BeginAnimate()
            {
                if (m_Image != null)
                {
                    //当gif动画每隔一定时间后,都会变换一帧,那么就会触发一事件,该方法就是将当前image每变换一帧时,都会调用当前这个委托所关联的方法。
                    ImageAnimator.Animate(m_Image, evtHandler);
                }
            }
    
            //委托所关联的方法
    
            private void OnImageAnimate(Object sender, EventArgs e)
            {
                //该方法中,只是使得当前这个winform重绘,然后去调用该winform的OnPaint()方法进行重绘)
                this.Invalidate();
            }
    
            //获得当前gif动画的下一步需要渲染的帧,当下一步任何对当前gif动画的操作都是对该帧进行操作)
    
            private void UpdateImage()
            {
                ImageAnimator.UpdateFrames(m_Image);
            }
    
            //关闭显示动画,该方法可以在winform关闭时,或者某个按钮的触发事件中进行调用,以停止渲染当前gif动画。
    
            private void StopAnimate()
            {
                m_Image = null;
                ImageAnimator.StopAnimate(m_Image, evtHandler);
            }
    
            private void FrmProcessing_Shown(object sender, EventArgs e)
            {
                if (this.workAction != null)
                {
                    workThread = new Thread(ExecWorkAction);
                    workThread.IsBackground = true;
                    workThread.Start();
                }
            }
    
            private void ExecWorkAction()
            {
                try
                {
                    var workTask = new Task((arg) =>
                                    {
                                        this.workAction(arg);
                                    },
                                this.workActionArg);
    
                    workTask.Start();
                    Task.WaitAll(workTask);
                }
                catch (Exception ex)
                {
                    this.WorkException = ex;
                }
                finally
                {
                    this.WorkCompleted = true;
                }
    
            }
        }
    }
    复制代码

    以下是自动生成的代码:

    复制代码
    namespace TEMS
    {
        partial class FrmProcessing
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Windows Form Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
                this.lbMessage = new System.Windows.Forms.Label();
                this.panImage = new System.Windows.Forms.Panel();
                this.tableLayoutPanel1.SuspendLayout();
                this.SuspendLayout();
                // 
                // tableLayoutPanel1
                // 
                this.tableLayoutPanel1.ColumnCount = 1;
                this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
                this.tableLayoutPanel1.Controls.Add(this.lbMessage, 0, 0);
                this.tableLayoutPanel1.Controls.Add(this.panImage, 0, 1);
                this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
                this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
                this.tableLayoutPanel1.Name = "tableLayoutPanel1";
                this.tableLayoutPanel1.RowCount = 2;
                this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
                this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
                this.tableLayoutPanel1.Size = new System.Drawing.Size(582, 318);
                this.tableLayoutPanel1.TabIndex = 1;
                // 
                // lbMessage
                // 
                this.lbMessage.BackColor = System.Drawing.Color.Transparent;
                this.lbMessage.Dock = System.Windows.Forms.DockStyle.Fill;
                this.lbMessage.Font = new System.Drawing.Font("微软雅黑", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
                this.lbMessage.Location = new System.Drawing.Point(3, 0);
                this.lbMessage.Name = "lbMessage";
                this.lbMessage.Padding = new System.Windows.Forms.Padding(0, 0, 0, 30);
                this.lbMessage.Size = new System.Drawing.Size(576, 159);
                this.lbMessage.TabIndex = 1;
                this.lbMessage.Text = "lbMessage
    adsfadsf";
                this.lbMessage.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
                // 
                // panImage
                // 
                this.panImage.Dock = System.Windows.Forms.DockStyle.Fill;
                this.panImage.Location = new System.Drawing.Point(3, 162);
                this.panImage.Name = "panImage";
                this.panImage.Size = new System.Drawing.Size(576, 153);
                this.panImage.TabIndex = 2;
                // 
                // FrmProcessing
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.BackColor = System.Drawing.SystemColors.Control;
                this.ClientSize = new System.Drawing.Size(582, 318);
                this.Controls.Add(this.tableLayoutPanel1);
                this.Cursor = System.Windows.Forms.Cursors.WaitCursor;
                this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                this.Name = "FrmProcessing";
                this.Opacity = 0.85D;
                this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
                this.Text = "FrmProcessing";
                this.Load += new System.EventHandler(this.FrmProcessing_Load);
                this.Shown += new System.EventHandler(this.FrmProcessing_Shown);
                this.tableLayoutPanel1.ResumeLayout(false);
                this.ResumeLayout(false);
    
            }
    
            #endregion
    
            private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
            private System.Windows.Forms.Label lbMessage;
            private System.Windows.Forms.Panel panImage;
    
    
        }
    }
    复制代码

    代码中SetWorkAction方法是用来设置异步需要处理的委托方法,在窗体显示出来后(FrmProcessing_Shown),创建新线程,用以处理耗时的逻辑代码段,其中有一个WorkCompleted属性,这个主要是表明处理耗时的逻辑代码已完成(不论是否报错),在窗体重绘时(OnPaint),会持续判断该值是否为true,若为true则关闭当前窗口。

    另之所以没重写Panel的OnPaint方法,原因是虽然可以显示动图,但由于局部重绘,造成动图出现闪屏,所以仍需要采用窗体重绘

    为了便于通用,我还定义了一个通用方法,专门用来显示遮罩层窗体,方法定义如下:

    复制代码
        public static class Common
        {
    
            public static void ShowProcessing(string msg, Form owner, ParameterizedThreadStart work, object workArg = null)
            {
                FrmProcessing processingForm = new FrmProcessing(msg);
                dynamic expObj = new ExpandoObject();
                expObj.Form = processingForm;
                expObj.WorkArg = workArg;
                processingForm.SetWorkAction(work, expObj);
                processingForm.ShowDialog(owner);
                if (processingForm.WorkException != null)
                {
                    throw processingForm.WorkException;
                }
            }
    
            
        }
    复制代码

    现在使用就很简单了,如下:

    Common.ShowProcessing("正在处理中,请稍候...", this, (obj) =>
    {
         //这里写处理耗时的代码,代码处理完成则自动关闭该窗口
    },null);

     使用效果如下:

  • 相关阅读:
    hdoj2187:悼念512汶川大地震遇难同胞 (贪心)
    2.0其它之Transform详解,以及UIElement和FrameworkElement的常用属性
    2.0外观之样式, 模板, 视觉状态和视觉状态管理器
    2.0图形之Ellipse, Line, Path, Polygon, Polyline, Rectangle
    2.0控件之ListBox, MediaElement, MultiScaleImage, PasswordBox, ProgressBar, RadioButton
    2.0画笔之SolidColorBrush, ImageBrush, VideoBrush, LinearGradientBrush, RadialGradientBrush
    2.0图形之基类System.Windows.Shapes.Shape
    2.0交互之鼠标事件和键盘事件
    2.0控件之ScrollViewer, Slider, StackPanel, TabControl, TextBlock, TextBox, ToggleButton
    2.0交互之InkPresenter(涂鸦板)
  • 原文地址:https://www.cnblogs.com/sjqq/p/6838561.html
Copyright © 2011-2022 走看看