Python GUI:Tkinter——06


本文将续上一章 Python GUI:Tkinter——05 ,没看过的同学可以看一下呀。

上一章中,我们已经将我们的 GUI 完善到比较精辟的程度。虽然控件、GUI 界面已经勉强差强人意了,但是里面的 bussiness logit 还是很傻瓜的。就线程方面来说,这个 GUI 属于单线程 application。那么,什么是线程?如何多线程?多线程有什么用?就是本章要学习的内容了。

线程与进程

进程即 process,线程为 thread。就咱们之前弄的 GUI 来说,他属于 单线程单进程。每当我们运行他的时候,就会在 windows 任务管理器中看到这个进程。然而,单一线程会让我们的 app 在运行长时间操作的时候,被冻住。

假设某个控件的触发函数,运行的时间比较长。那么你会发现,咱们这个 GUI 会原地“冻结”,使得我们之后的某些触发(你可以点鼠标)不会被响应。并常见的,会弹出一个“未响应”窗口叫你结束进程。

实际上,这就是单线程引起的。当我们的 GUI 被运行时,系统就会分配给你的 GUI 一个主线程。因此,如果主线程被占用,那么 GUI 也就被冻住了。所以,为了解决这个问题,我们需要给那些花费时间可能较长的触发函数,单独分配一个线程。还有另一种解决方式,就是给分配多 process。 但是进程之间通常不共享数据和代码,线程之间则相反。如果要让进程相互“沟通”的话,需要一种叫 IPC 的高端技术。而线程不用,一个进程中的多个线程,他们彼此共享代码和数据,因此不用操心 IPC 这一块。

如何多线程呢?下一节!

多线程实现

class OOP 下面 加入代码:
......
    def methodInAThread(self):
        print('你好吗?')
        for idx in range(5):    #模拟长时间触发事件
            sleep(1)   
            self.aScrTxt.insert(tk.INSERT,str(idx)+'\n')
    def createThread(self):
        runT = Thread(target=self.methodInAThread)    #创建一个线程,线程运行 methodInAThread
        runT.setDaemon(True)    #将线程设置成守护线程
        runT.start()
......

什么叫守护线程呢?这是因为如果创建一个线程后,即便主线程关闭了,这个子线程也会继续运行下去,直到任务的终结。将其设置成守护线程,表示该线程是不重要的,进程退出时不需要等待这个线程执行完成。这样做的意义在于:避免子线程无限死循环,导致退不出程序,也就是避免传说中的孤儿进程。

更专业的说,setDaemon()设置为True, 则主线程执行完毕后会将子线程回收掉,设置为false,主进程执行结束时不会回收子线程。另外,其需要在 start 方法前调用;

队列

队列有什么用? 队列是 FIFO 的东西,即先进先出。他可以帮助我们实现多个输出任务的管理。

想来看看他的使用,首先修改程序:

from queue import Queue
续上
    def methodInAThread(self):
        print('你好吗?')
        for idx in range(5):
            sleep(1)
            self.aScrTxt.insert(tk.INSERT,str(idx)+'\n')
        sleep(1)
        
    def createThread(self):
        runT = Thread(target=self.methodInAThread)
        runT.setDaemon(True)
        runT.start()
        
        writeT = Thread(target=self.useQueues,daemon=True)
        writeT.start()
        
   def useQueues(self):
        guiQueue = Queue()
        print(guiQueue)
        for idx in range(10):
            guiQueue.put('Message from a queue'+str(idx))
        while True:
            print(guiQueue.get())

言归正传,我们的队列用于解决什么问题呢?假设我们的 scrolledtext 控件要展示的信息,来源于多个不同的控件(不单单是一个 button 啦),这时候,我们就要用到 queue 来帮助我们管理这些信息来源了。

另外,queue 还能够帮助我们加强多个 .py 文件的交互,即实现多文本开发的解耦

GUI 与 Business logic 分开

在开发一个 GUI 应用时,人们总想着把 GUI 控件定义部分、和控件逻辑功能部分的代码拆分开。也就是说,将 GUI 和 business logic 分开。如何分开,可以巧妙地利用 self 指针。

首先我们新建一个文件:logicpart.py,在下面输入代码:

def writeToScrol(inst):
    print('hi from Queue',inst)
    inst.createThread()

之后,我们就没必要在 clickBut 函数中调用 createThread 了,修改成如下即可:

    def _clickBut(self):
        self.aButton.configure(text='hello'+self.aEntry.get()+self.aCombobox.get())
        # mBox.showerror('错误提示框','你没有错,是我错了')
        # self.createThread()
        logicpart.writeToScrol(self)

当然,这似乎并没有降低我们的麻烦。实际上,我们可以灵活使用 self 指针,从而将 methodInAThread 、createThread 什么的都给分开。怎么分开,请到评论区中一叙。

总结

本章介绍的内容短小精悍。在很多 GUI 中,都有打开一个对话框,然后选择文件这一操作。如何弄呢?请看下一章 Python GUI:Tkinter——07

猜你喜欢

转载自blog.csdn.net/weixin_42141390/article/details/106537893