如何在不冻结其他所有内容的情况下不断更新Tkinter?

时间:2018-12-08 14:45:58

标签: python multithreading user-interface tkinter

我需要从另一个线程向tkinter发送更新,应该立即处理。每当我尝试多线程时,可悲的是Tkinter会死机。

我的尝试:

我已经阅读了多个Tkinter线程页面,但是没有找到任何有效的方法,因为大多数页面尝试在 button.click()上创建一个新线程,但没有在这里提供帮助。

我尝试不调用 .mainloop()而是在每次更新进来时自己调用更新函数:

#GUI    
def update(self, string):
        self._interactor.config(text=string)
        #interactor is a button
        self._tk.update_idletasks()
        self._tk.update()

这很好,直到我在master中使用带有sleep()的循环来不断更新文本。 GUI和master在sleep()期间被冻结。 因此,我尝试使用threaded timer as discussed here

#MASTER
gui=gui_remote(self)

def changetext():
    text=self.gettextsomewhere() 
    self._gui.update(text)

loop=RepeatedTimer(5, changetext)

但这只会导致Tkinter引发以下错误:

  

RuntimeError:主线程不在主循环中

如何解决这个问题很困难。可以在主线程上调用GUI类,并且仍然可以正确访问其功能吗?

我如何到达这一点:

对于我的项目,我需要一个按钮,它代表多个按钮。
每y(例如1.5)秒,显示的文本应从外部更新为新的文本。
另外,我想将GUI,Controller和Data分开(使用蓝图方法),以便以后对它们中的每个进行调整都更加容易。

我已经使用 TK的.after()函数使它起作用,但是我不得不同时使用GUI和控制功能。

我的计划

具有一个GUI类,该类可以通过简单的公共函数从另一个对象更新。另一个对象(主对象)应该能够创建一个GUI对象,并每隔y秒用新数据调用GUI的更新函数。 单击GUI按钮时,每次只需在master上调用某个方法:

#GUI example
from tkinter import Tk, Button, Frame, Label

class gui_sample:

    def __init__(self, master):
        """This is the very simple GUI"""
        self._master=master
        self._tk=Tk()
        self._interactor= Button(self._tk, text="Apfelsaft", command=self._click)
        self._interactor.pack()
        self._tk.mainloop()

    def update(self, string):
        """Handle interactor update"""
        self._interactor.config(text=string)

    def _click(self):
        self._master.click()


#MASTER
from gui_module import *

class Controller:

    def __init__(self):
        self._gui=gui_sample(self)
        self._run()

    def _run(self):
        #call this every 5 seconds
        new_text=self.gettextfromsomewhere()
        self._gui.update(new_text)

    def click():
        #do something
        pass
#this code is just a blueprint it probably does nothing

我的问题:

我不希望母版使用TK功能,因为稍后我可能会切换到另一个UI模块并保留母版的功能。主机将不断循环显示接下来显示的内容,并且需要同时进行访问。与sleep()一起使用循环不是一个好主意,因为它们会同时阻塞主程序和GUI。调用.mainloop()也是有问题的,因为它将阻塞所有其他程序。 gui应该始终响应更新,而不要求更新。

0 个答案:

没有答案