很酷的单独线程splash开机画面C#代码

这篇博客分享了一种用C#实现的开机启动画面技术,该启动画面采用单独线程运行,支持实时更新进度条。通过调用`SplashScreen.ShowSplashScreen()`显示启动画面,并使用`SplashScreen.SetStatus(moduleName)`来更新状态信息。为了防止主线程与启动画面线程冲突,推荐使用`OnAppIdle`在进程空闲时启动主线程。源代码提供了一个渐入渐出效果良好的启动画面,可以方便地修改背景图片并添加计时器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

逛逛sourceforge,有时候会有不错的东西能淘到,就比如这个开机画面的Form就不错,(在一个report的项目里,出处又是别的地方。。。)。要用的话,把代码拷过来,在form里改改背景图片,就可以了,对了还得加个timer。这个类用静态方法包装了一个线程,在开机的时候单独执行,渐入渐出也很好控制,尤为好的是在splash的时候就可以向里面实时的写进度条了,而不是先设置好了格子。。。开始的时候用这个方法就可以激活了:

SplashScreen.ShowSplashScreen();

写信息是用这个方法,不会阻塞怎么写都行,嘿嘿:

SplashScreen.SetStatus(moduleName);

不过,为了避免一开始程序的时候执行splash以及主线程会抢,还是用个OnAppIdle在进程空闲的时候开始执行主线程为好。

  static void Main()
  {
   System.Windows.Forms.Application.Idle += new EventHandler(OnAppIdle)

....................................

OnAppIdle里这样写:当然为了达到这点,得把进程的context提出来

  private static System.Windows.Forms.ApplicationContext context;
  private static MainForm mForm  = new MainForm();

  private static void OnAppIdle(object sender, EventArgs e)
  {
   if(context.MainForm == null)
   {
    // first we remove the eventhandler
    System.Windows.Forms.Application.Idle -= new EventHandler(OnAppIdle);

//调用SplashScreen.ShowSplashScreen();写点东西

...................................

     // now we set the main form for the context...
    context.MainForm = mForm;

    // ...show it...调用主form
    context.MainForm.Show();

................................................................

 

接下来就是splash的代码了:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using Microsoft.Win32;

namespace SplashDemo
{
 /// <summary>
 /// Splash screen implemented by Tom Clement, see the CodeProject
 /// http://www.codeproject.com/csharp/PrettyGoodSplashScreen.asp
 /// </summary>
 public class SplashScreen : System.Windows.Forms.Form
 {
  // Threading
  static SplashScreen ms_frmSplash = null;
  static Thread ms_oThread = null;

  // Fade in and out.
  private double m_dblOpacityIncrement = .05;
  private double m_dblOpacityDecrement = .08;
  private const int TIMER_INTERVAL = 50;

  // Status and progress bar
  static string ms_sStatus;
  private double m_dblCompletionFraction = 0;
  private Rectangle m_rProgress;

  // Progress smoothing
  private double m_dblLastCompletionFraction = 0.0;
  private double m_dblPBIncrementPerTimerInterval = .015;

  // Self-calibration support
  private bool m_bFirstLaunch = false;
  private DateTime m_dtStart;
  private bool m_bDTSet = false;
  private int m_iIndex = 1;
  private int m_iActualTicks = 0;
  private ArrayList m_alPreviousCompletionFraction;
  private ArrayList m_alActualTimes = new ArrayList();
  private const string REG_KEY_INITIALIZATION = "Initialization";
  private const string REGVALUE_PB_MILISECOND_INCREMENT = "Increment";
  private const string REGVALUE_PB_PERCENTS = "Percents";

  private System.Windows.Forms.Label lblStatus;
  private System.Windows.Forms.Label lblTimeRemaining;
  private System.Windows.Forms.Timer timer1;
  private System.Windows.Forms.Panel pnlStatus;
  private System.ComponentModel.IContainer components;

  /// <summary>
  /// Constructor
  /// </summary>
  public SplashScreen()
  {
   InitializeComponent();
   this.Opacity = .00;
   timer1.Interval = TIMER_INTERVAL;
   timer1.Start();
   this.ClientSize = this.BackgroundImage.Size;
  }

  /// <summary>
  /// Clean up any resources being used.
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if(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.components = new System.ComponentModel.Container();
   System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(SplashScreen));
   this.lblStatus = new System.Windows.Forms.Label();
   this.pnlStatus = new System.Windows.Forms.Panel();
   this.lblTimeRemaining = new System.Windows.Forms.Label();
   this.timer1 = new System.Windows.Forms.Timer(this.components);
   this.SuspendLayout();
   //
   // lblStatus
   //
   this.lblStatus.BackColor = System.Drawing.Color.Transparent;
   this.lblStatus.Location = new System.Drawing.Point(336, 345);
   this.lblStatus.Name = "lblStatus";
   this.lblStatus.Size = new System.Drawing.Size(335, 15);
   this.lblStatus.TabIndex = 0;
   this.lblStatus.DoubleClick += new System.EventHandler(this.SplashScreen_DoubleClick);
   //
   // pnlStatus
   //
   this.pnlStatus.BackColor = System.Drawing.Color.Transparent;
   this.pnlStatus.Location = new System.Drawing.Point(58, 370);
   this.pnlStatus.Name = "pnlStatus";
   this.pnlStatus.Size = new System.Drawing.Size(614, 11);
   this.pnlStatus.TabIndex = 1;
   this.pnlStatus.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlStatus_Paint);
   this.pnlStatus.DoubleClick += new System.EventHandler(this.SplashScreen_DoubleClick);
   //
   // lblTimeRemaining
   //
   this.lblTimeRemaining.BackColor = System.Drawing.Color.Transparent;
   this.lblTimeRemaining.Location = new System.Drawing.Point(336, 388);
   this.lblTimeRemaining.Name = "lblTimeRemaining";
   this.lblTimeRemaining.Size = new System.Drawing.Size(335, 17);
   this.lblTimeRemaining.TabIndex = 2;
   this.lblTimeRemaining.Text = "Time remaining";
   this.lblTimeRemaining.DoubleClick += new System.EventHandler(this.SplashScreen_DoubleClick);
   //
   // timer1
   //
   this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
   //
   // SplashScreen
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.BackColor = System.Drawing.Color.LightGray;
   this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
   this.ClientSize = new System.Drawing.Size(768, 456);
   this.Controls.Add(this.lblTimeRemaining);
   this.Controls.Add(this.pnlStatus);
   this.Controls.Add(this.lblStatus);
   this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
   this.Name = "SplashScreen";
   this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
   this.Text = "SplashScreen";
   this.TopMost = true;
   this.DoubleClick += new System.EventHandler(this.SplashScreen_DoubleClick);
   this.ResumeLayout(false);

  }
  #endregion

  // ************* Static Methods *************** //

  // A static method to create the thread and
  // launch the SplashScreen.
  static public void ShowSplashScreen()
  {
   // Make sure it's only launched once.
   if( ms_frmSplash != null )
    return;
   ms_oThread = new Thread( new ThreadStart(SplashScreen.ShowForm));
   ms_oThread.IsBackground = true;
   ms_oThread.ApartmentState = ApartmentState.STA;
   ms_oThread.Start();
   
  }

  // A property returning the splash screen instance
  static public SplashScreen SplashForm
  {
   get
   {
    return ms_frmSplash;
   }
  }

  // A private entry point for the thread.
  static private void ShowForm()
  {
   ms_frmSplash = new SplashScreen();
   Application.Run(ms_frmSplash);
  }

  // A static method to close the SplashScreen
  static public void CloseForm()
  {
   if( ms_frmSplash != null && ms_frmSplash.IsDisposed == false )
   {
    // Make it start going away.
    ms_frmSplash.m_dblOpacityIncrement = - ms_frmSplash.m_dblOpacityDecrement;
   }
   ms_oThread = null; // we don't need these any more.
   ms_frmSplash = null;
  }

  // A static method to set the status and update the reference.
  static public void SetStatus(string newStatus)
  {
   SetStatus(newStatus, true);
  }

  // A static method to set the status and optionally update the reference.
  // This is useful if you are in a section of code that has a variable
  // set of status string updates.  In that case, don't set the reference.
  static public void SetStatus(string newStatus, bool setReference)
  {
   ms_sStatus = newStatus;
   if( ms_frmSplash == null )
    return;
   if( setReference )
    ms_frmSplash.SetReferenceInternal();
  }

  // Static method called from the initializing application to
  // give the splash screen reference points.  Not needed if
  // you are using a lot of status strings.
  static public void SetReferencePoint()
  {
   if( ms_frmSplash == null )
    return;
   ms_frmSplash.SetReferenceInternal();

  }

  // ************ Private methods ************

  // Internal method for setting reference points.
  private void SetReferenceInternal()
  {
   if( m_bDTSet == false )
   {
    m_bDTSet = true;
    m_dtStart = DateTime.Now;
    ReadIncrements();
   }
   double dblMilliseconds = ElapsedMilliSeconds();
   m_alActualTimes.Add(dblMilliseconds);
   m_dblLastCompletionFraction = m_dblCompletionFraction;
   if( m_alPreviousCompletionFraction != null && m_iIndex < m_alPreviousCompletionFraction.Count )
    m_dblCompletionFraction = (double)m_alPreviousCompletionFraction[m_iIndex++];
   else
    m_dblCompletionFraction = ( m_iIndex > 0 )? 1: 0;
  }

  // Utility function to return elapsed Milliseconds since the
  // SplashScreen was launched.
  private double ElapsedMilliSeconds()
  {
   TimeSpan ts = DateTime.Now - m_dtStart;
   return ts.TotalMilliseconds;
  }

  // Function to read the checkpoint intervals from the previous invocation of the
  // splashscreen from the registry.
  private void ReadIncrements()
  {
   string sPBIncrementPerTimerInterval = RegistryAccess.GetStringRegistryValue( REGVALUE_PB_MILISECOND_INCREMENT, "0.0015");
   double dblResult;

   if( Double.TryParse(sPBIncrementPerTimerInterval, System.Globalization.NumberStyles.Float, System.Globalization.NumberFormatInfo.InvariantInfo, out dblResult) == true )
    m_dblPBIncrementPerTimerInterval = dblResult;
   else
    m_dblPBIncrementPerTimerInterval = .0015;

   string sPBPreviousPctComplete = RegistryAccess.GetStringRegistryValue( REGVALUE_PB_PERCENTS, "" );

   if( sPBPreviousPctComplete != "" )
   {
    string [] aTimes = sPBPreviousPctComplete.Split(null);
    m_alPreviousCompletionFraction = new ArrayList();

    for(int i = 0; i < aTimes.Length; i++ )
    {
     double dblVal;
     if( Double.TryParse(aTimes[i], System.Globalization.NumberStyles.Float, System.Globalization.NumberFormatInfo.InvariantInfo, out dblVal) )
      m_alPreviousCompletionFraction.Add(dblVal);
     else
      m_alPreviousCompletionFraction.Add(1.0);
    }
   }
   else
   {
    m_bFirstLaunch = true;
    lblTimeRemaining.Text = "";
   }
  }

  // Method to store the intervals (in percent complete) from the current invocation of
  // the splash screen to the registry.
  private void StoreIncrements()
  {
   string sPercent = "";
   double dblElapsedMilliseconds = ElapsedMilliSeconds();
   for( int i = 0; i < m_alActualTimes.Count; i++ )
    sPercent += ((double)m_alActualTimes[i]/dblElapsedMilliseconds).ToString("0.####", System.Globalization.NumberFormatInfo.InvariantInfo) + " ";

   RegistryAccess.SetStringRegistryValue( REGVALUE_PB_PERCENTS, sPercent );

   m_dblPBIncrementPerTimerInterval = 1.0/(double)m_iActualTicks;
   RegistryAccess.SetStringRegistryValue( REGVALUE_PB_MILISECOND_INCREMENT, m_dblPBIncrementPerTimerInterval.ToString("#.000000", System.Globalization.NumberFormatInfo.InvariantInfo));
  }

  //********* Event Handlers ************

  // Tick Event handler for the Timer control.  Handle fade in and fade out.  Also
  // handle the smoothed progress bar.
  private void timer1_Tick(object sender, System.EventArgs e)
  {
   lblStatus.Text = ms_sStatus;

   if( m_dblOpacityIncrement > 0 )
   {
    m_iActualTicks++;
    if( this.Opacity < 1 )
     this.Opacity += m_dblOpacityIncrement;
   }
   else
   {
    if( this.Opacity > 0 )
     this.Opacity += m_dblOpacityIncrement;
    else
    {
     StoreIncrements();
     this.Close();
     Trace.WriteLine("Called this.Close()");
    }
   }
   if( m_bFirstLaunch == false && m_dblLastCompletionFraction < m_dblCompletionFraction )
   {
    m_dblLastCompletionFraction += m_dblPBIncrementPerTimerInterval;
    int width = (int)Math.Floor(pnlStatus.ClientRectangle.Width * m_dblLastCompletionFraction);
    int height = pnlStatus.ClientRectangle.Height;
    int x = pnlStatus.ClientRectangle.X;
    int y = pnlStatus.ClientRectangle.Y;
    if( width > 0 && height > 0 )
    {
     m_rProgress = new Rectangle( x, y, width, height);
     pnlStatus.Invalidate(m_rProgress);
     int iSecondsLeft = 1 + (int)(TIMER_INTERVAL * ((1.0 - m_dblLastCompletionFraction)/m_dblPBIncrementPerTimerInterval)) / 1000;
     if( iSecondsLeft == 1 )
      lblTimeRemaining.Text = string.Format( "1 second remaining");
     else
      lblTimeRemaining.Text = string.Format( "{0} seconds remaining", iSecondsLeft);

    }
   }
  }

  // Paint the portion of the panel invalidated during the tick event.
  private void pnlStatus_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
  {
   if( m_bFirstLaunch == false && e.ClipRectangle.Width > 0 && m_iActualTicks > 1 )
   {
    LinearGradientBrush brBackground = new LinearGradientBrush(m_rProgress, Color.FromArgb(58, 96, 151), Color.FromArgb(181, 237, 254), LinearGradientMode.Horizontal);
    e.Graphics.FillRectangle(brBackground, m_rProgress);
   }
  }

  // Close the form if they double click on it.
  private void SplashScreen_DoubleClick(object sender, System.EventArgs e)
  {
   CloseForm();
  }
 }

 /// <summary>
 /// A class for managing registry access.
 /// </summary>
 public class RegistryAccess
 {
  private const string SOFTWARE_KEY = "Software";
  private const string COMPANY_NAME = "Netron";
  private const string APPLICATION_NAME = "Cobalt";

  // Method for retrieving a Registry Value.
  static public string GetStringRegistryValue(string key, string defaultValue)
  {
   RegistryKey rkCompany;
   RegistryKey rkApplication;

   rkCompany = Registry.CurrentUser.OpenSubKey(SOFTWARE_KEY, false).OpenSubKey(COMPANY_NAME, false);
   if( rkCompany != null )
   {
    rkApplication = rkCompany.OpenSubKey(APPLICATION_NAME, true);
    if( rkApplication != null )
    {
     foreach(string sKey in rkApplication.GetValueNames())
     {
      if( sKey == key )
      {
       return (string)rkApplication.GetValue(sKey);
      }
     }
    }
   }
   return defaultValue;
  }

  // Method for storing a Registry Value.
  static public void SetStringRegistryValue(string key, string stringValue)
  {
   RegistryKey rkSoftware;
   RegistryKey rkCompany;
   RegistryKey rkApplication;

   rkSoftware = Registry.CurrentUser.OpenSubKey(SOFTWARE_KEY, true);
   rkCompany = rkSoftware.CreateSubKey(COMPANY_NAME);
   if( rkCompany != null )
   {
    rkApplication = rkCompany.CreateSubKey(APPLICATION_NAME);
    if( rkApplication != null )
    {
     rkApplication.SetValue(key, stringValue);
    }
   }
  }
 }

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值