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) / ;
int y = ;
//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) / , (screenRect.Height - this.Height) / );
} //为委托关联一个处理方法
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 = ;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.lbMessage, , );
this.tableLayoutPanel1.Controls.Add(this.panImage, , );
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(, );
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = ;
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(, );
this.tableLayoutPanel1.TabIndex = ;
//
// 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)()));
this.lbMessage.Location = new System.Drawing.Point(, );
this.lbMessage.Name = "lbMessage";
this.lbMessage.Padding = new System.Windows.Forms.Padding(, , , );
this.lbMessage.Size = new System.Drawing.Size(, );
this.lbMessage.TabIndex = ;
this.lbMessage.Text = "lbMessage\r\nadsfadsf";
this.lbMessage.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
//
// panImage
//
this.panImage.Dock = System.Windows.Forms.DockStyle.Fill;
this.panImage.Location = new System.Drawing.Point(, );
this.panImage.Name = "panImage";
this.panImage.Size = new System.Drawing.Size(, );
this.panImage.TabIndex = ;
//
// 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(, );
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);
使用效果如下:

大家可以将上述代码直接复制到新建的窗体中,即可立即使用,上述代码若有不足之处,还请大家评论并指出,谢谢!
Winform应用程序实现通用遮罩层的更多相关文章
- Winform应用程序实现通用遮罩层二
之前先后发表过:<Winform应用程序实现通用遮罩层>.<Winform应用程序实现通用消息窗口>,这两款遮罩层其实都是基于弹出窗口的,今天为大家分享一个比较简单但界面相对友 ...
- Winform应用程序实现通用消息窗口
记得我之前发表过一篇文章<Winform应用程序实现通用遮罩层>,是实现了透明遮罩的消息窗口,功能侧重点在动图显示+消息提醒,效果看上去比较的炫,而本篇我又来重新设计通用消息窗口,功能重点 ...
- WinForm特效:桌面上的遮罩层
一个窗体特效,帮你了解几个windows api函数.效果:windows桌面上增加一个简单的遮罩层,其中WS_EX_TRANSPARENT 比较重要,它实现了鼠标穿透的功能. using Syste ...
- [C#] (原创)一步一步教你自定义控件——06,MaskLayer(遮罩层)
一.前言 技术没有先进与落后,只有合适与不合适. 本篇的自定义控件是:遮罩层(MaskLayer). 遮罩层对软件的美观与易用性上的提高是很大的,在日常使用过程中也会经常看到各种遮罩层,虽然WinFo ...
- 微信小程序遮罩层覆盖input失效
问题:微信小程序中,我们常使用遮罩层,如点击按钮弹出下拉框.弹框等等.若在遮罩层下存在input.textarea.canvas.camera.map.video等标签时,会出现遮罩层覆盖失效的问题. ...
- C# Winform 实现自定义半透明loading加载遮罩层
在网页中通过div+css实现半透明效果不难,今天我们看看一种在winfrom中实现的方法: 效果图如下,正常时: 显示遮罩层时: 自定义遮罩层控件的源码如下: View Row Code 1 usi ...
- 微信小程序弹出和隐藏遮罩层动画以及五星评分
参考源码: http://www.see-source.com/weixinwidget/detail.html?wid=82 https://blog.csdn.net/pcaxb/article/ ...
- C# Winform 实现自定义半透明遮罩层介绍
在网页中通过div+css实现半透明效果不难,今天我们看看一种在winfrom中实现的方法: 效果图如下,正常时: 显示遮罩层时: 自定义遮罩层控件的源码如下: View Row Code 1 usi ...
- [微信小程序]实现一个自定义遮罩层
正文: 先上效果图: 点击按钮Show显示遮罩层,再次点击屏幕任何地方隐藏遮罩层; <button bindtap="showview">Show</button ...
随机推荐
- SQL入门经典(九) 之自定义函数
UDF和存储过程很类似,用户自定义函数是一组有序的T-SQL语句,这些语句被预先优化和编译,并且可以作为一个单元来测试调用.UDF和存储过程的主要区别在于结果返回方式,为了能支持更多返回值,UDF比存 ...
- 软件工程课设day3
下载昨日新版本程序,完成修复项目的测试. 与组内成员讨论,确认项目新模块功能“吐槽墙”的设计方向与实现形式——因为项目为便捷工具类,社区形式的实现方式与项目本质背道而驰.因此决定以“点击目标课程条目, ...
- Angularjs中文版本开发指南发布
从本人开始在写关于Angularjs的文章开始,也算是见证了Angularjs在国内慢慢的火起来,如今的Angularjs正式如日中天.想知道为什么Angularjs会这么火,请移步angularjs ...
- Git学习笔记(10)——搭建Git服务器
本文主要记录了Git服务器的搭建,以及一些其他的配置,和最后的小总结. Git远程仓库服务器 其实远程仓库和本地仓库没啥不同,远程仓库只是每天24小时开机为大家服务,所以叫做服务器.我们完全可以把自己 ...
- tomcat项目无法发布异常,Could not copy all resources to .........(转)
[plain] <span style="font-size:18px;">Deployment failure on Tomcat 6.x. Could not c ...
- iOS 打包iPa
http://blog.fir.im/how-to-build-adhoc-ipa/ 之前都是打包好ipa然后发送给客户,特麻烦,fir.im网站不错 迅速获取自己手机的udid: http://f ...
- 10 个 Redis 建议/技巧
转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/145.html?1455790611 Redis 在当前的技术社区里是非常 ...
- mybatis结合分页的使用及解析.
首先说明: 这里分页是使用了SSM框架+ jsp 来做的, 当然分页还有其他的很多做法, 比如easyUI自带的分页效果. 但是这些原理都是很相似的, 再次只做为学习总结之用. 一, 效果图这里的截图 ...
- iOS-工厂模式
概述 在前面两章中,分别介绍了简单工厂模式和工厂方法模式,我们知道简单工厂模式的优点是去除了客户端与具体产品的依赖,缺点是违反了“开放-关闭原则”:工厂方法模式克服了简单工厂模式的缺点,将产品的创建工 ...
- Android 控件架构及View、ViewGroup的测量
附录:示例代码地址 控件在Android开发的过程中是必不可少的,无论是我们在使用系统控件还是自定义的控件.下面我们将讲解一下Android的控件架构,以及如何实现自定义控件. 1.Android控件 ...