简体   繁体   English

使用线程更新 Tkinter GUI

[英]Updating Tkinter GUI w/ threading

I am working on a project that follows the basic structure: a sequencer class instantiates a GUI class that provides functionality to update/modify content on the GUI (change background image, update text fields, etc.).我正在开发一个遵循基本结构的项目:一个音序器类实例化一个 GUI 类,该类提供更新/修改 GUI 内容的功能(更改背景图像、更新文本字段等)。 In the sequencer class, I want to kick off some method run_test that performs some actions (including some time.sleep() commands, and also updates the GUI to show that the test is running. Obviously, the GUI mainloop freezes when this occurs and the GUI does not update.在排序器类中,我想启动一些执行某些操作(包括一些run_test time.sleep()命令,并更新 GUI 以显示测试正在运行的方法 run_test。显然,GUI 主循环在发生这种情况时会冻结,并且GUI 不会更新。

What's the right solution here?这里的正确解决方案是什么? How do I kick off the run_test in another thread so that the GUI can update?如何在另一个线程中启动 run_test 以便 GUI 可以更新?

class TestSequencer():

    def __init__(self):
        self._gui = TestGUI(sequencer=self)
        self._gui.run_gui()

    def start_sequencer(self):
        self._gui.update_background_image()
        self.run_test()

    def run_test(self):
        time.sleep(5)

The result is such that the code sleeps for 5 seconds, after which the GUI updates the background image.结果是代码休眠 5 秒,之后 GUI 更新背景图像。 I want it to occur immediately, and potentially on the fly as various things occur during run_test (eg depending on pass/fail of run_test, show different things on the GUI).我希望它立即发生,并且可能随着 run_test 期间发生的各种事情而动态发生(例如,根据 run_test 的通过/失败,在 GUI 上显示不同的内容)。

How do I accomplish this?!我该如何实现?!

I have some code here that might help you.我这里有一些代码可以帮助你。 I have already faced your problem and I figure it out with threading another class that will run my code.我已经遇到了你的问题,我通过线程另一个将运行我的代码的类来解决这个问题。 So unfortunately I cannot show the entire code but i tried to give you something that can help.所以不幸的是我不能显示整个代码,但我试图给你一些可以帮助的东西。

DELAY = 100  # millisecs between status label updates

# global flag and a Lock to control concurrent access to it
run_flag_lock = threading.Lock()
running = False

class RunningClass(threading.Thread):
    def __init__(self):
        self.run()

    def run(self):
        global running
        # random work
        YOUR CODE
        with run_flag_lock:
            running = False

class GUI(Frame, object):
    def __init__(self, master)
        super(GUI, self).__init__(master)
        global running
        self.button = Button(self, text="EXECUTE", command=lambda: self.execute(), bg="green", fg='white')
        self.button.grid(row=0, column=0, sticky=E + W)
        with run_flag_lock:
            running = False
        self.after(DELAY, self.update_status, None)  # start status widget updating

    def update_status(self, run_state):
        global running
        """ Update status label text and state of buttons to match running flag. """
        # no need to declare run_flag_lock global since it's not being assigned a value
        with run_flag_lock:
            if running != run_state:  # status change?
                if running:
                    run_state = True
                else:
                    run_state = False
            else:
                try:
                    x = self.temp
                except:
                    pass
        # run again after a delay to repeat status check
        self.after(DELAY, self.update_status, run_state)


    def execute(self):
        global running
        flag_error = False
        with run_flag_lock:
            if not running:
                self.temp = RunningClass()
                self.temp.start()
                running = True

if __name__ == '__main__':
    ROOT = Tk()
    ROOT.title("TEXT")
    LOGIN = GUI(ROOT)
    LOGIN.grid(sticky=E)
    ROOT.mainloop()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM