线程完成时触发事件

时间:2018-04-11 12:55:35

标签: python multithreading tkinter

嗨Python和Tkinter Gurus, 我正在尝试构建一个具有两个按钮的简单GUI。单击Button时,会启动一个线程来完成一些工作。这项工作通常需要10秒/ 15秒。 GUI也可以正常工作。

但是我想实现一个弹出窗口来通知哪个线程已经完成。我检查了t.isAlive()函数并且无法实现它,因为我不知道如何在主循环中基于isAlive触发事件。

这是我的示例代码

from threading import Thread
from time import sleep
import Tkinter
import ttk

class SmallGui:
    def __init__(self, master):
        self.master = master
        self.master.title('test gui')

        self.button_1 = ttk.Button(self.master,
                                   text='Start 1',
                                   command=lambda: self.init_thread(1))

        self.button_2 = ttk.Button(self.master,
                                   text='Start 2',
                                   command=lambda: self.init_thread(2))

        self.button_1.pack()
        self.button_2.pack()

    def init_thread(self, work):
        if work == 1:
            t = Thread(target=self.work_1)
            t.start()
        else:
            t = Thread(target=self.work_2)
            t.start()

    @staticmethod
    def work_1():
        print 'Work 1 started'
        # Do some Task and return a list
        sleep(10)

    @staticmethod
    def work_2():
        print 'Work 2 Started'
        # Do some Task and return a list
        sleep(15)


if __name__ == '__main__':
    root = Tkinter.Tk()
    run_gui = SmallGui(root)
    root.mainloop()

1 个答案:

答案 0 :(得分:1)

您可以使用tkinter的消息框。 Tkinter有一个内置方法,可用于各种弹出消息或问题。在这里,我们将使用messagebox.showinfo

我正在使用Python 3.X,所以我添加了一个适用于3.X和2.X版python的导入方法。

from threading import Thread
from time import sleep

try:
    import Tkinter as tk
    import tkMessageBox as mb
    import ttk
except ImportError:
    import tkinter as tk
    from tkinter import messagebox as mb
    import tkinter.ttk as ttk

class SmallGui:
    def __init__(self, master):
        self.master = master
        self.master.title('test gui')

        self.button_1 = ttk.Button(self.master,
                                   text='Start 1',
                                   command=lambda: self.init_thread(1))

        self.button_2 = ttk.Button(self.master,
                                   text='Start 2',
                                   command=lambda: self.init_thread(2))

        self.button_1.pack()
        self.button_2.pack()

    def init_thread(self, work):
        if work == 1:
            t = Thread(target=self.work_1)
            t.start()
        else:
            t = Thread(target=self.work_2)
            t.start()

    @staticmethod
    def work_1():
        print ('Work 1 started')
        # Do some Task and return a list
        sleep(1)
        mb.showinfo("test", "Work 1 complete")

    @staticmethod
    def work_2():
        print ('Work 2 Started')
        # Do some Task and return a list
        sleep(1)
        mb.showinfo("test", "Work 2 complete")


if __name__ == '__main__':
    root = tk.Tk()
    run_gui = SmallGui(root)
    root.mainloop()

更新:

无论出于何种原因,我的上述解决方案在python 3中工作,但在2.7.14中没有。

但是下面的例子在2.7.14中有用,应该适合你。

我在这里做的是创建2个类属性来监视每个线程。 我创建了一个方法,如果线程处于活动状态,将检查1秒钟,如果线程变为非活动状态,则会弹出消息框。

from threading import Thread
from time import sleep

import Tkinter as tk
import tkMessageBox as mb
import ttk


class SmallGui(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.master = master
        self.master.title('test gui')

        self.button_1 = ttk.Button(self.master,
                                   text='Start 1',
                                   command=lambda: self.init_thread(1))

        self.button_2 = ttk.Button(self.master,
                                   text='Start 2',
                                   command=lambda: self.init_thread(2))

        self.button_1.pack()
        self.button_2.pack()

        self.work1_status = None
        self.work2_status = None

    def init_thread(self, work):
        if work == 1:
            self.work1_status = Thread(target=self.work_1)
            self.work1_status.start()
            self.check_thread(self.work1_status, work)
        else:
            self.work2_status = Thread(target=self.work_2)
            self.work2_status.start()
            self.check_thread(self.work2_status, work)

    def check_thread(self, pass_thread, thread_name):
        if pass_thread.isAlive() == False:
                pass_thread = None
                mb.showinfo("test", "Work {} complete".format(thread_name))
        else:
            self.after(1000, lambda: self.check_thread(pass_thread, thread_name))

    @staticmethod
    def work_1():
        print ('Work 1 started')
        # Do some Task and return a list
        sleep(5)

    @staticmethod
    def work_2():
        print ('Work 2 Started')
        # Do some Task and return a list
        sleep(5)

if __name__ == '__main__':
    root = tk.Tk()
    run_gui = SmallGui(root)
    root.mainloop()