在等待线程完成时冻结/挂起 tkinter GUI [英] Freezing/Hanging tkinter GUI in waiting for the thread to complete

查看:26
本文介绍了在等待线程完成时冻结/挂起 tkinter GUI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的界面在按下按钮时冻结.我正在使用线程,但我不确定为什么仍然挂起.任何帮助将不胜感激.提前致谢

My interface is freezing on pressing the button. I am using threading but I am not sure why is still hanging. Any help will be appreciated. Thanks in advance

class magic:
    def __init__(self):
        self.mainQueue=queue.Queue()

    def addItem(self,q):
        self.mainQueue.put(q)

    def startConverting(self,funcName):
        if(funcName=="test"):
            while not self.mainQueue.empty():
                t = Thread(target = self.threaded_function)
                t.start()
                t.join()

    def threaded_function(self):

        time.sleep(5)
        print(self.mainQueue.get())

m=magic()
def helloCallBack():
   m.addItem("asd")
   m.startConverting("test")  //this line of code is freezing

B = tkinter.Button(top, text ="Hello", command = helloCallBack)

B.pack()
top.mainloop()

推荐答案

这是使用基于 tkinter 的 GUI 执行异步任务的方法.我根据引用的书中的食谱改编了它.您应该能够对其进行修改以执行您需要的操作.

Here's a recipe for doing an asynchronous task with a tkinter-based GUI. I adapted it from a recipe in the cited book. You should be able to modify it to do what you need.

要保持 GUI 响应,需要通过执行类似join()的后台线程来干扰它的mainloop()——使 GUI挂起"直到线程完成.这是通过使用通用的after() 小部件方法以定期轮询一个Queue.

To keep the GUI responsive requires not interfering with its mainloop() by doing something like join()ing a background thread—which makes the GUI "hang" until the thread is finished. This is accomplished by using the universal after() widget method to poll a Queue at regular intervals.

# from "Python Coobook 2nd Edition", section 11.9, page 439.
# Modified to work in Python 2 & 3.
from __future__ import print_function

try:
    import Tkinter as tk, time, threading, random, Queue as queue
except ModuleNotFoundError:   # Python 3
    import tkinter as tk, time, threading, random, queue

class GuiPart(object):
    def __init__(self, master, queue, end_command):
        self.queue = queue
        # Set up the GUI
        tk.Button(master, text='Done', command=end_command).pack()
        # Add more GUI stuff here depending on your specific needs

    def processIncoming(self):
        """ Handle all messages currently in the queue, if any. """
        while self.queue.qsize():
            try:
                msg = self.queue.get_nowait()
                # Check contents of message and do whatever is needed. As a
                # simple example, let's print it (in real life, you would
                # suitably update the GUI's display in a richer fashion).
                print(msg)
            except queue.Empty:
                # just on general principles, although we don't expect this
                # branch to be taken in this case, ignore this exception!
                pass


class ThreadedClient(object):
    """
    Launch the main part of the GUI and the worker thread. periodic_call()
    and end_application() could reside in the GUI part, but putting them
    here means that you have all the thread controls in a single place.
    """
    def __init__(self, master):
        """
        Start the GUI and the asynchronous threads.  We are in the main
        (original) thread of the application, which will later be used by
        the GUI as well.  We spawn a new thread for the worker (I/O).
        """
        self.master = master
        # Create the queue
        self.queue = queue.Queue()

        # Set up the GUI part
        self.gui = GuiPart(master, self.queue, self.end_application)

        # Set up the thread to do asynchronous I/O
        # More threads can also be created and used, if necessary
        self.running = True
        self.thread1 = threading.Thread(target=self.worker_thread1)
        self.thread1.start()

        # Start the periodic call in the GUI to check the queue
        self.periodic_call()

    def periodic_call(self):
        """ Check every 200 ms if there is something new in the queue. """
        self.master.after(200, self.periodic_call)
        self.gui.processIncoming()
        if not self.running:
            # This is the brutal stop of the system.  You may want to do
            # some cleanup before actually shutting it down.
            import sys
            sys.exit(1)

    def worker_thread1(self):
        """
        This is where we handle the asynchronous I/O.  For example, it may be
        a 'select()'.  One important thing to remember is that the thread has
        to yield control pretty regularly, be it by select or otherwise.
        """
        while self.running:
            # To simulate asynchronous I/O, create a random number at random
            # intervals. Replace the following two lines with the real thing.
            time.sleep(rand.random() * 1.5)
            msg = rand.random()
            self.queue.put(msg)

    def end_application(self):
        self.running = False  # Stops worker_thread1 (invoked by "Done" button).

rand = random.Random()
root = tk.Tk()
client = ThreadedClient(root)
root.mainloop()

这篇关于在等待线程完成时冻结/挂起 tkinter GUI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆