【问题标题】:splashscreen not closing properly闪屏未正确关闭
【发布时间】:2013-06-03 10:58:36
【问题描述】:

我遇到了一些我无法自行解决的奇怪问题...我使用线程创建了启动画面(Form3 ~ SplashScreen),不知何故在应用程序到达部件之后

thread.Abort();

(实际上会杀死线程)闪屏会一直停留在屏幕上,直到我将鼠标移到它上面,或者在其他表单(例如 Form1)上的某个位置单击它...我变得更加困惑,因为这并没有当我运行应用程序时发生在 VS 中。启动画面正在正确关闭......,它只发生在编译的 .exe 上 程序.cs

     namespace ICAMReports
 {
     static class Program
    {

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
 }

SplashScreen.cs

    namespace ICAMReports
{
    public partial class SplashScreen : Form
    {
        public SplashScreen()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            progressBar1.Increment(1);
            if (progressBar1.Value == 100)
            {
                timer1.Stop();
            }
        }
    }
}

Form1.cs

    namespace ICAMReports
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Thread th = new Thread(new ThreadStart(splashScreen));
            th.Start();
            Thread.Sleep(3000);
            th.Abort();
        }
        public void splashScreen()
        {
            Application.Run(new SplashScreen());
        }
       //this where the rest of code is placed....
    }
}

任何线索,为什么会发生这种情况或如何解决这个问题?

截图:

【问题讨论】:

  • 我不知道你怎么能在同一个问题中拥有thread.Abort 和“正常关闭”
  • thread.Abort 实际上是 th.Abort();在 Form1.cs
  • 据我所知;线程.睡眠(3000); -> 停止当前线程,th.Abort(); -> 杀死线程(并因此关闭 SplashScreen 表单......)如果我错了,请纠正我......
  • 线程睡眠使线程进入睡眠状态,然后线程中止可能会关闭表单,但它会不自然地这样做
  • 好的,但是如果它关闭表单,为什么启动画面仍然在屏幕上......,直到:(我按键盘上的键或单击启动屏幕或其他表单),好像还在记忆中……(请参考我上传的图片)

标签: c# multithreading screen splash-screen


【解决方案1】:

MSDN 说关于 thread.Abort,“调用这个方法通常会终止线程。”

有无数种方法可以在不使用 thread.Abort 的情况下关闭启动画面。

这是完成您正在尝试做的事情的一种方法。

SplashScreen.cs

    namespace ICAMReports
{
public partial class SplashScreen : Form
{
    ManualResetEventSlim splashDone;
    public SplashScreen(ManualResetEventSlim SplashDone)
    {
     splashDone=SplashDone;
        InitializeComponent();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        progressBar1.Increment(1);
        if (progressBar1.Value == 100)
        {
            splashDone.Set();
            this.Close();
        } } } }

Form1.CS

      namespace ICAMReports
{
public partial class Form1 : Form
{
    ManualResetEventSlim splashDone = new ManualResetEventSlim(false);
    public Form1()
    {
        InitializeComponent();
        Thread th = new Thread(new ThreadStart(splashScreen));
        th.Start();
        splashDone.Wait();
    }
    public void splashScreen()
    {
        Application.Run(new SplashScreen(splashDone));
    }
   //this where the rest of code is placed....
    }
    }

splashDone.Wait() 将完成您尝试使用 Sleep() 执行的相同操作,但您应该使用启动画面中的加载栏来告诉您何时结束线程。实际上,在这种情况下,将启动画面放在单独的线程上确实没有任何意义,因为睡眠/等待会暂停主窗体加载任何内容,直到启动画面完成。假设您的 Form1 中有资源密集型的东西,您想在启动画面分散用户注意力时加载这些东西。你会做这样的事情,而不是完全暂停 Form1(因为使用单独线程的全部意义在于它们都同时运行。

SplashScreen.cs

    namespace ICAMReports
{
public partial class SplashScreen : Form
{
    Form parent;
    delegate void show();
    public SplashScreen(Form Parent)
    {
     parent=Parent;
        InitializeComponent();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        progressBar1.Increment(1);
        if (progressBar1.Value == 100)
        {
            parent.Invoke(new show(()=>{parent.Opacity=100;}));
            this.Close();
        } } } }

Form1.CS

      namespace ICAMReports
{
public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
        Thread th = new Thread(new ThreadStart(splashScreen));
        th.Start();
        this.Opacity=0;
    }
    public void splashScreen()
    {
        Application.Run(new SplashScreen(this));
    }
   //this where the rest of code is placed....
    }
    }

编辑:响应加载条动画

加载栏会根据您使用的 Windows 的版本和设置而移动,并且看起来会有所不同。您不能使用 Thread.Sleep 让加载条赶上,因为它会暂停 loadingBar1 动画。你需要给你的加载栏大约 10% 来赶上(根据需要调整它)这应该可以解决你的加载栏动画问题。

    int i = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        if(i++<100)progressBar1.Value++;
        if (i == 110)
        {
         splashDone.Set();
         this.Close();
        }
    }

【讨论】:

  • 第一个代码有效,它修复了关闭初始屏幕(表单),但由于某种原因,progressbar1 没有达到 100,它以大约 75% 的速度关闭表单...
  • 您需要让计时器多走几下才能让动画完成更新。我在上面编辑了我的帖子,为您提供了一种可能的解决方案。只需创建一个单独的变量,该变量可以超过最大 progressBar1 值并在等于 110 或您希望确保加载条动画完成的任何时间间隔时退出。我测试了上面的 110 设置,它给了动画足够的时间来完成。如果您需要它持续更长时间,如果您希望它更快一点,请增加数字 105 勉强能坚持到最后。
  • 感谢 CodeCamper,尽管我不明白为什么之前的代码不起作用...,以及为什么我需要将值设置为 100 以上...
  • Thread.Abort 不会关闭线程,它只会向应该关闭的线程发送信号。由于无数种原因,线程可能永远不会收到信号,或者比您预期的要晚得多。可能是因为没有引发任何事件,所以在引发某些事件(例如鼠标移动事件)之前,表单永远不会意识到信号。您没有将加载条的值设置为 100 以上,您必须将第二个值设置为 100 以上的原因是为了给加载条动画一些时间来完成加载,因为默认的 windows 7/8 加载动画具有内置延迟。
  • 感谢 CodeCamper,很抱歉用这么简单的代码打扰您...,我是 C# 新手,目前正在学习该编程语言,您的代码再次帮助我实现我想要的,并提供帮助我明白该怎么做...非常感谢您的帮助...!干杯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 2011-11-03
  • 2019-12-20
  • 2011-03-08
相关资源
最近更新 更多