如果程序在装载时需要进行较长时间的处理,最好使用启动画面,一方面美化程序,一方面可以不使用户面对着一片空白的程序界面。
我手头上一个小项目主界面启动时需要检查用户文件及运行环境是否有效,需要一段时间处理,因此想到要添加一个启动画面,在网上搜了一阵,发现下面两个方案:
1、用C#给程序加启动画面并只允许一个应用程序实例运行
http://www.zahui.com/html/14/36790.htm
2、HOW TO:溅射屏幕(Splash Screen),也叫程序启动画面的制作(.NET2003)
http://lzmtw.cnblogs.com/archive/2005/10/31/265782.html
第一个方案在实现与界面分离上做得不够好,启动界面(一个窗体)依赖于特定窗体,主窗体还必须添加一个PreLoad方法完成装载任务,只能在代码级重用。而且那个只允许一个实例的写法也太....
第二个方案框架很好,但细微处理可能存在一点问题,需要判断主窗体的WindowState,整个代码也较复杂。
我改动了一下,基本结构仿照第二个方案。
功能:为程序添加启动界面,显示启动界面的同时加载主窗体,主窗体加载完毕后关闭启动界面,显示主窗体。启动画面停留的时间是设定的时间和主窗体装载所需时间两个的最大值。启动画面在另一个线程上运行。
plus:我的水平还很差,见笑。
程序代码如下:
//启动窗体虚基类,继承自ApplicationContext
using System.Windows.Forms;
using System.Threading;
using System;
//启动画面虚基类,启动画面会停留一段时间,该时间是设定的时间和主窗体构造所需时间两个的最大值
public abstract class SplashScreenApplicationContext : ApplicationContext
{
private Form _SplashScreenForm;//启动窗体
private Form _PrimaryForm;//主窗体
private System.Timers.Timer _SplashScreenTimer;
private int _SplashScreenTimerInterVal = 5000;//默认是启动窗体显示5秒
private bool _bSplashScreenClosed = false;
private delegate void DisposeDelegate();//关闭委托,下面需要使用控件的Invoke方法,该方法需要这个委托
public SplashScreenApplicationContext()
{
this.ShowSplashScreen();//这里创建和显示启动窗体
this.MainFormLoad();//这里创建和显示启动主窗体
}
protected abstract void OnCreateSplashScreenForm();
protected abstract void OnCreateMainForm();
protected abstract void SetSeconds();
protected Form SplashScreenForm
{
set
{
this._SplashScreenForm = value;
}
}
protected Form PrimaryForm
{//在派生类中重写OnCreateMainForm方法,在MainFormLoad方法中调用OnCreateMainForm方法
// ,在这里才会真正调用Form1(主窗体)的构造函数,即在启动窗体显示后再调用主窗体的构造函数
// ,以避免这种情况:主窗体构造所需时间较长,在屏幕上许久没有响应,看不到启动窗体
set
{
this._PrimaryForm = value;
}
}
protected int SecondsShow
{//未设置启动画面停留时间时,使用默认时间
set
{
if (value != 0)
{
this._SplashScreenTimerInterVal = 1000 * value;
}
}
}
private void ShowSplashScreen()
{
this.SetSeconds();
this.OnCreateSplashScreenForm();
this._SplashScreenTimer = new System.Timers.Timer(((double)(this._SplashScreenTimerInterVal)));
_SplashScreenTimer.Elapsed += new System.Timers.ElapsedEventHandler(new System.Timers.ElapsedEventHandler(this.SplashScreenDisplayTimeUp));
this._SplashScreenTimer.AutoReset = false;
Thread DisplaySpashScreenThread = new Thread(new ThreadStart(DisplaySplashScreen));
DisplaySpashScreenThread.Start();
}
private void DisplaySplashScreen()
{
this._SplashScreenTimer.Enabled = true;
Application.Run(this._SplashScreenForm);
}
private void SplashScreenDisplayTimeUp(object sender, System.Timers.ElapsedEventArgs e)
{
this._SplashScreenTimer.Dispose();
this._SplashScreenTimer = null;
this._bSplashScreenClosed = true;
}
private void MainFormLoad()
{
this.OnCreateMainForm();
while (!(this._bSplashScreenClosed))
{
Application.DoEvents();
}
DisposeDelegate SplashScreenFormDisposeDelegate = new DisposeDelegate(this._SplashScreenForm.Dispose );
this._SplashScreenForm.Invoke(SplashScreenFormDisposeDelegate);
this._SplashScreenForm = null;
//必须先显示,再激活,否则主窗体不能在启动窗体消失后出现
this._PrimaryForm.Show();
this._PrimaryForm.Activate();
this._PrimaryForm.Closed += new EventHandler(_PrimaryForm_Closed);
}
private void _PrimaryForm_Closed(object sender, EventArgs e)
{
base.ExitThread();
}
}
使用方法:定义一个启动类,应用程序从启动类启动,该类会使用继承自启动窗体虚基类的一个启动窗体类,在该类中定义启动窗体和主窗体。启动窗体和主窗体的代码略去,注意要删除机器生成的窗体代码的Main方法部分。
public class StartUpClass
{
[STAThread]
static void Main()
{
Application.Run(new mycontext());
}
}
//启动窗体类(继承自启动窗体虚基类),启动画面会停留一段时间,该时间是设定的时间和主窗体构造所需时间两个的最大值
public class mycontext : SplashScreenApplicationContext
{
protected override void OnCreateSplashScreenForm()
{
this.SplashScreenForm = new FormStart();//启动窗体
}
protected override void OnCreateMainForm()
{
this.PrimaryForm = new FormMain();//主窗体
}
protected override void SetSeconds()
{
this.SecondsShow = 2;//启动窗体显示的时间(秒)
}
}
我手头上一个小项目主界面启动时需要检查用户文件及运行环境是否有效,需要一段时间处理,因此想到要添加一个启动画面,在网上搜了一阵,发现下面两个方案:
1、用C#给程序加启动画面并只允许一个应用程序实例运行
http://www.zahui.com/html/14/36790.htm
2、HOW TO:溅射屏幕(Splash Screen),也叫程序启动画面的制作(.NET2003)
http://lzmtw.cnblogs.com/archive/2005/10/31/265782.html
第一个方案在实现与界面分离上做得不够好,启动界面(一个窗体)依赖于特定窗体,主窗体还必须添加一个PreLoad方法完成装载任务,只能在代码级重用。而且那个只允许一个实例的写法也太....
第二个方案框架很好,但细微处理可能存在一点问题,需要判断主窗体的WindowState,整个代码也较复杂。
我改动了一下,基本结构仿照第二个方案。
功能:为程序添加启动界面,显示启动界面的同时加载主窗体,主窗体加载完毕后关闭启动界面,显示主窗体。启动画面停留的时间是设定的时间和主窗体装载所需时间两个的最大值。启动画面在另一个线程上运行。
plus:我的水平还很差,见笑。
程序代码如下:
//启动窗体虚基类,继承自ApplicationContext
using System.Windows.Forms;
using System.Threading;
using System;
//启动画面虚基类,启动画面会停留一段时间,该时间是设定的时间和主窗体构造所需时间两个的最大值
public abstract class SplashScreenApplicationContext : ApplicationContext
{
private Form _SplashScreenForm;//启动窗体
private Form _PrimaryForm;//主窗体
private System.Timers.Timer _SplashScreenTimer;
private int _SplashScreenTimerInterVal = 5000;//默认是启动窗体显示5秒
private bool _bSplashScreenClosed = false;
private delegate void DisposeDelegate();//关闭委托,下面需要使用控件的Invoke方法,该方法需要这个委托
public SplashScreenApplicationContext()
{
this.ShowSplashScreen();//这里创建和显示启动窗体
this.MainFormLoad();//这里创建和显示启动主窗体
}
protected abstract void OnCreateSplashScreenForm();
protected abstract void OnCreateMainForm();
protected abstract void SetSeconds();
protected Form SplashScreenForm
{
set
{
this._SplashScreenForm = value;
}
}
protected Form PrimaryForm
{//在派生类中重写OnCreateMainForm方法,在MainFormLoad方法中调用OnCreateMainForm方法
// ,在这里才会真正调用Form1(主窗体)的构造函数,即在启动窗体显示后再调用主窗体的构造函数
// ,以避免这种情况:主窗体构造所需时间较长,在屏幕上许久没有响应,看不到启动窗体
set
{
this._PrimaryForm = value;
}
}
protected int SecondsShow
{//未设置启动画面停留时间时,使用默认时间
set
{
if (value != 0)
{
this._SplashScreenTimerInterVal = 1000 * value;
}
}
}
private void ShowSplashScreen()
{
this.SetSeconds();
this.OnCreateSplashScreenForm();
this._SplashScreenTimer = new System.Timers.Timer(((double)(this._SplashScreenTimerInterVal)));
_SplashScreenTimer.Elapsed += new System.Timers.ElapsedEventHandler(new System.Timers.ElapsedEventHandler(this.SplashScreenDisplayTimeUp));
this._SplashScreenTimer.AutoReset = false;
Thread DisplaySpashScreenThread = new Thread(new ThreadStart(DisplaySplashScreen));
DisplaySpashScreenThread.Start();
}
private void DisplaySplashScreen()
{
this._SplashScreenTimer.Enabled = true;
Application.Run(this._SplashScreenForm);
}
private void SplashScreenDisplayTimeUp(object sender, System.Timers.ElapsedEventArgs e)
{
this._SplashScreenTimer.Dispose();
this._SplashScreenTimer = null;
this._bSplashScreenClosed = true;
}
private void MainFormLoad()
{
this.OnCreateMainForm();
while (!(this._bSplashScreenClosed))
{
Application.DoEvents();
}
DisposeDelegate SplashScreenFormDisposeDelegate = new DisposeDelegate(this._SplashScreenForm.Dispose );
this._SplashScreenForm.Invoke(SplashScreenFormDisposeDelegate);
this._SplashScreenForm = null;
//必须先显示,再激活,否则主窗体不能在启动窗体消失后出现
this._PrimaryForm.Show();
this._PrimaryForm.Activate();
this._PrimaryForm.Closed += new EventHandler(_PrimaryForm_Closed);
}
private void _PrimaryForm_Closed(object sender, EventArgs e)
{
base.ExitThread();
}
}
使用方法:定义一个启动类,应用程序从启动类启动,该类会使用继承自启动窗体虚基类的一个启动窗体类,在该类中定义启动窗体和主窗体。启动窗体和主窗体的代码略去,注意要删除机器生成的窗体代码的Main方法部分。
public class StartUpClass
{
[STAThread]
static void Main()
{
Application.Run(new mycontext());
}
}
//启动窗体类(继承自启动窗体虚基类),启动画面会停留一段时间,该时间是设定的时间和主窗体构造所需时间两个的最大值
public class mycontext : SplashScreenApplicationContext
{
protected override void OnCreateSplashScreenForm()
{
this.SplashScreenForm = new FormStart();//启动窗体
}
protected override void OnCreateMainForm()
{
this.PrimaryForm = new FormMain();//主窗体
}
protected override void SetSeconds()
{
this.SecondsShow = 2;//启动窗体显示的时间(秒)
}
}