Cross-thread cross-form. Display a splash screen with a progress bar

若如初见. 提交于 2019-12-24 10:47:44

问题


My Solution:

So I managed to find another tutorial http://www.codeproject.com/KB/dotnet/Yet_Another_Splash_Screen.aspx and the sourcecode seemed to make more sense to me. Here is the code i'm using now. Main() is left untouched.

Splash.cs

`

public partial class Frm_Splash : Form { delegate void ProgressDelegate(int percent); delegate void SplashShowCloseDelegate();

    /// <summary>
    /// To ensure splash screen is closed using the API and not by keyboard or any other things
    /// </summary>
    bool CloseSplashScreenFlag = false;

    /// <summary>
    /// Base constructor
    /// </summary>
    /// 
    public Frm_Splash()
    {
        InitializeComponent();
        progress_Splash.Show();
        this.ClientSize = this.BackgroundImage.Size;
    }

    public void ShowSplashScreen()
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new SplashShowCloseDelegate(ShowSplashScreen));
            return;
        }
        this.Show();
        Application.Run(this);
    }

    /// <summary>
    /// Closes the SplashScreen
    /// </summary>
    public void CloseSplashScreen()
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new SplashShowCloseDelegate(CloseSplashScreen));
            return;
        }
        CloseSplashScreenFlag = true;
        this.Close();
    }

    /// <summary>
    /// Update text in default green color of success message
    /// </summary>
    /// <param name="Text">Message</param>
    public void Progress(int percent)
    {
        if (InvokeRequired)
        {
            // We're not in the UI thread, so we need to call BeginInvoke
            BeginInvoke(new ProgressDelegate(Progress), new object[] { percent });
            return;
        }
        // Must be on the UI thread if we've got this far
        progress_Splash.Value = percent;
        // Fade in the splash screen - looks pro. :D
       if (percent < 10)
            this.Opacity = this.Opacity + .15;
    }


    /// <summary>
    /// Prevents the closing of form other than by calling the CloseSplashScreen function
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void SplashForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (CloseSplashScreenFlag == false)
            e.Cancel = true;
    }
 }`

Form1.cs

public partial class Frm_Main : Form
{
    Frm_Splash frm_Splash = new Frm_Splash();

    public Frm_Main()
    {
        this.Hide();
        Thread splashthread = new Thread(new ThreadStart(frm_Splash.ShowSplashScreen));
        splashthread.IsBackground = true;
        splashthread.Start();
        InitializeComponent();
        CenterToScreen();
    }

    private void Frm_Main_Load(object sender, EventArgs e)
    {
        if (PassedAll() == true)
            FillMovieLB();
        if (FillMovieProgress == 100)
        {
            //Throw in this sleep so the user can see the progress bar reach all the way to the end.
            Thread.Sleep(1000);
            this.Show();
            frm_Splash.CloseSplashScreen();
            this.Activate();
        }
    }

Original Question

G'day all,

I'm very new to programming in C# and i'm having a problem with the http://www.codeproject.com/KB/cs/prettygoodsplashscreen.aspx tutorial and implementing it within my application. I'm finding it a little difficult to understand what the problem is. I know there is alot of stuff about getting this splash screen to work but I can't get my head around it.

When I start the program, the Frm_Main will display, you can see the listbox being populated, because i've placed it in BackgroundWorker.DoWork(), and then afterwards my frm_Splash will show after the work is done. Obviously, the way it should be working is, frm_Splash will show during the work being done on Frm_Main, and the progress bar will show the progress of the loading (this part I haven't implemented yet).

Edit: I may not have been clear, but the question is: How can I get my splashscreen to display while the work is being done and before the main form is displayed?

Thanks everybody. :)

Here is my code:

   static Frm_Splash frm_Splash = new Frm_Splash();

    public delegate void ShowFormDelegate();

    public void ShowForm()
    {
        frm_Splash.Show();
    }

    public Frm_Main()
    {
        InitializeComponent();
        CenterToScreen();
        if (PassedAll() == true)
        {
            back_loadprog.RunWorkerAsync();  
        }
    }

   private void back_loadprog_DoWork(object sender, DoWorkEventArgs e)
    {
        Invoke(new ShowFormDelegate(ShowForm));
        Invoke(new FillMovieLBDelegate(FillMovieLB));
    }

回答1:


Here, have some code... Works for me.

Splash Form:

namespace Screens.Forms
{
    public partial class Splash : DevExpress.XtraEditors.XtraForm
    {
        public Splash()
        {
            InitializeComponent();
        }
        string RandomLoadingMessage()
        {
            string[] lines ={
                "Pripremam warp pogon",
                "Moj drugi ekran za učitavanje je brži, probaj njega",
                "Verzija programa koju imam u testiranju imala je smiješnije poruke"
            };
            return lines[new Random().Next(lines.Length)];
        }
        public void RandomizeText()
        {
            lblMessage.Text = RandomLoadingMessage();
        }
        private void Splash_Load(object sender, EventArgs e)
        {
            RandomizeText();
        }
        private static Splash _splash;
        private static bool _shouldClose;

        static void ThreadFunc()
        {
            _splash = new Splash();
            _splash.Show();
            while (!_shouldClose)
            {
                Application.DoEvents();
                Thread.Sleep(100);
                if (new Random().Next(1000) < 10)
                {
                    _splash.Invoke(new MethodInvoker(_splash.RandomizeText));
                }
            }
            for (int n = 0; n < 18; n++)
            {
                Application.DoEvents();
                Thread.Sleep(60);
            }
            if (_splash != null)
            {
                _splash.Close();
                _splash = null;
            }
        }
        static public void ShowSplash()
        {
            _shouldClose = false;
            Thread t = new Thread(ThreadFunc);
            t.Priority = ThreadPriority.Lowest;
            t.Start();
        }
        internal static void RemoveSplash()
        {
            _shouldClose = true;
        }
        internal static void ShowSplash(List<string> fromTwitterMessages)
        {
            ShowSplash();
        }
    }
}

Show it with:

Splash.ShowSplash();

Do the work you need, then when done:

Splash.RemoveSplash();



回答2:


You need to take this a step further back to your Main() function of the application. In general you could do this:

  • Create a ManualResetEvent or better ManualResetEventSlim if you are on .NET 4
  • Start a new thread displaying your SplashScreen, use Application.Run
  • In your SplashScreen you should create a time which polls the created ManualResetEvent frequently, a nice animation could be placed here also
  • If the event is set you should close the form
  • Back in your Main() do your stuff like creating forms etc.
  • When finish set the event, so that the SplashScreen can be closed
  • To be sure that your MainForm is not shown before your SplashScreen is closed you can use another event


来源:https://stackoverflow.com/questions/6692115/cross-thread-cross-form-display-a-splash-screen-with-a-progress-bar

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!