zoukankan      html  css  js  c++  java
  • BusyTipOperator——显示提示窗体的实现(一)

    这是自己平时根据自己需要写的一些小代码,未必对大家有用。另外,这是根据个人想法而写,未必严谨和符合设计原则,若有任何不妥之处,还请不吝赐教。

    提示窗体在所有软件中都是必不可少的。其特征在于按需显示一个对话框,原操作界面被禁用,程序继续运行;工作完成后,再将对话框关闭。

    看似很简单的一个功能,但由于涉及到了线程、窗体之间的微妙关系,其实现要比想象中的要复杂得多。

    最简单的办法是,直接在工作中调用Form.Show显示提示窗体,然后继续工作,完成后调用Form.Close关闭提示窗体。使用这个方法的程序看起来能够正常工作,不过,由于非模态窗口与创建窗口共用窗口线程,因此,实际上,调用Show后,虽然提示窗体能够显示,程序也没有被阻止,但由于窗口线程仍在执行工作,因此提示窗口将无法响应,其界面也将无法刷新。

    既然不能在同一个线程中,那自然就新建个线程来显示了。

    FrmFlexLabelTest dialog = new FrmFlexLabelTest();
    
    Thread th = new Thread(new ThreadStart(dialog.Show));
    
    th.Start();
    
    Thread.Sleep(5000);
    
    dialog.Invoke(new ThreadStart(dialog.Close));

    看起来挺好一段代码,不过执行后就会发现问题所在。程序执行后,弹出窗体一闪即逝,主窗体等待5秒后恢复正常。仔细一想,就不难发现问题所在:由于Show是非阻止函数,线程th在执行完dialog.Show使窗体显示出来之后就立即退出了,而由于dialog在线程th上显示,th的终止也导致了dialog的关闭。

    然后,这里有一点小小的疑问。调用了dialog.Show的线程为什么没有成为窗体线程呢?哈,突然想到了Program.cs的里那句Application.Run,找出来看了一下提示:在当前线程上创建一个标准消息循环…。果不其然,看来问题在这个,那就改在th上调用Application.Run好了:

            private void button4_Click(object sender, EventArgs e)
            {
                FrmFlexLabelTest dialog = new FrmFlexLabelTest();
    
                Thread th = new Thread(new ParameterizedThreadStart(this.Run));
    
                th.Start(dialog);
    
                Thread.Sleep(5000);
    
                dialog.Invoke(new ThreadStart(dialog.Close));
            }
    
            public void Run(object obj)
            {
                Application.Run(obj as Form);
            }

    再执行一遍,这次终于正常了。弹出窗体能够响应和被关闭,原线程也未阻塞。基本上,用上面的方式就能实现一个用于显示提示窗体的功能接口了。当然,由于ShowDialog是阻塞函数,将Application.Run换成ShowDialog也可达到同样的效果。

    不过,这样的一个实现虽然可用,但其效率却让人难以恭维。使用Show打开的窗体关闭后,窗体即被销毁,同时消息循环的终止也导致窗体线程的终止。也就是说,每显示一次提示窗体的代价是创建一个窗体、销毁一个窗体、创建一个线程并为其创建消息队列。显然,这样的代价很难让人接受。那么,又应当如何提高改进呢?同样显然的是,在一次程序运行期间,提示窗体总是要显示很多次。因此,若能重用窗体对象与线程,则可以均分创建、销毁它们的代价。要达到重用的目的,上述代码需要做两个改变:

    1.  使用ShowDialog显示提示窗体,使窗体对象可重复显示。

    2.  让线程在循环中调用ShowDialog显示窗体,窗体关闭后线程即转入挂起或休眠,直到需要再次显示窗体时被唤醒。

    注(疑问):其实ShowDialog也应该是创建一个新线程来作为窗体线程的,这么说来的,创建线程和消息队列的代价似乎不可避免。

  • 相关阅读:
    有了这个算法,图像上文字擦除再也用不上PS了
    说说Golang goroutine并发那些事儿
    Redis Sentinel 源码:Redis的高可用模型分析
    从架构设计理念到集群部署,全面认识KubeEdge
    如何极速极速搭建个人博客?Copy攻城狮用的这一招很优秀!
    Python进阶丨如何创建你的第一个Python元类?
    逼疯UE设计师,不可不知的提升产品用户体验的10个测试方法
    一文总结GaussDB通信原理知识
    目标检测推理部署:优化和部署
    GPU上的快速光谱图分区
  • 原文地址:https://www.cnblogs.com/yedaoq/p/1701014.html
Copyright © 2011-2022 走看看