python“tkinter和线程化”:;“主线程不在主循环中”;

python“tkinter和线程化”:;“主线程不在主循环中”;,python,multithreading,canvas,tkinter,Python,Multithreading,Canvas,Tkinter,我正在为我的公司开发一个“多层”GUI来监控温度和状态。因为我是python编程新手,所以我的代码需要一些帮助 快速代码解释: 代码由类构成。“Main”初始化主窗口(tkinter)并创建其他要显示的帧(如果需要)。除“canvas”外,其他每个类都是一个框架,它将显示不同的内容 每个画布中都包含一个图像和一些文本/变量文本。 线程用于从数据库获取数据并更改画布中的文本 问题是: 每次线程访问画布并尝试更改文本或创建新文本时,都会抛出错误“主线程不在主循环中” Exception in thr

我正在为我的公司开发一个“多层”GUI来监控温度和状态。因为我是python编程新手,所以我的代码需要一些帮助

快速代码解释: 代码由类构成。“Main”初始化主窗口(tkinter)并创建其他要显示的帧(如果需要)。除“canvas”外,其他每个类都是一个框架,它将显示不同的内容

每个画布中都包含一个图像和一些文本/变量文本。 线程用于从数据库获取数据并更改画布中的文本

问题是: 每次线程访问画布并尝试更改文本或创建新文本时,都会抛出错误
“主线程不在主循环中”

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.4/threading.py", line 868, in run
    self._target(*self._args, **self._kwargs)
  File "/home/pi/Documents/Programme/MM/TEST_Dateien/TEST_QUEUE.py", line 154, in __call__
    canvUbersicht.create_text(500,500, text="HOIIIIII")
  File "/usr/lib/python3.4/tkinter/__init__.py", line 2345, in create_text
    return self._create('text', args, kw)
  File "/usr/lib/python3.4/tkinter/__init__.py", line 2321, in _create
    *(args + self._options(cnf, kw))))
RuntimeError: main thread is not in main loop
如果我在不调用画布的情况下初始化线程(例如,
“print(“hey”)
),那么一切都正常

我的mainloop/mainthread从哪里开始,在哪里结束

我已经阅读了几个问题并重新安排了代码/线程,但它不会改变任何东西

如果有人能帮助我,我会非常高兴的

重要代码:

from tkinter import*
from DataSQL import*

class Main(Tk):
    def __init__(self, vollbild=False):
        print("Main INIT")
        Tk.__init__(self)                               #Initialisieren von Tkinter und somit erzeugen des Fensters
        Tk.geometry(self, ("1920x1080"))                #setzen von verschiedenen Parametern für das Fenster
        Tk.title(self, ("Laborüberwachung"))
        Tk.wm_overrideredirect(self, vollbild)

        container = Frame(self)                             #Frame "container" wird im eigenen Objekt(also main fenster) erstellt
        container.pack(side="top",fill="both",expand=True)  #Platzieren des Frames und ausfüllen des ganzen Fensters
        container.grid_rowconfigure(0, weight=1)            #Platzieren im Grid
        container.grid_columnconfigure(0, weight=1)         #Platzieren im Grid
        
        self.frames = {}                                #Erstellt leere Liste
        
        for F in (Ubersicht, Settings, Pin, BR167, BR213, Star3, Telematik):
            frame = F(container, self)                  #Objekt frame wird erzeugt durch aufruf von Konstruktoren der Klassen(Frameklassen zB "Übersicht")
            self.frames[F] = frame                      #Objekte werden in der Liste gespeichert, unter dem Namen der Klasse(zB "frames[Übersicht]")
            frame.grid(row=0, column=0, sticky="nsew")  #Platzieren des Frames im Grid, wobei das Grid aus nur einem Feld besteht, wird nur für die Funktionalität benötigt

        self.show_frame(Ubersicht)                      #Zeigt immer die Übersichtsseite bei StartUp
        #print(self.frames)

    def show_frame(self, cnt):                         #Methode zum Framewechsel und somit umschalten zwischen 'Tabs'
        frame = self.frames[cnt]
        frame.tkraise()
        print("frame raised",cnt)


class Ubersicht(Frame):

    def __init__(self, parent, controller):
        print("Ubersicht INIT")
        Frame.__init__(self, parent)
        
        self.interfaceImage = PhotoImage(file="/home/pi/Documents/Programme/Laborueberwachung3/IMG 1080/Übersicht.png")
        canvUbersicht = canv(self, controller, img=self.interfaceImage, Uber=1)
 
        self.__eventExit = threading.Event()
        self.__thread = threading.Thread(target=self, args=(canvUbersicht, self.__eventExit,))
        self.__thread.start()
        
    def __call__(self,canvUbersicht,stop_event):
        while not stop_event.wait(1):
            canvUbersicht.create_text(500,500,text="HEY")

class canv(Canvas):
    def __init__(self, parent, controller, img=None, Uber=None):
        Canvas.__init__(self, parent)
        print("canvas INIT")
        self.config(width=1920,height=1080)
        self.place(x=0,y=0)
        if (img != None):
            self.create_image(0,0,anchor=NW,image=img)
            
        if (Uber == 1):
            clickAreaSettings = self.create_rectangle(0,0,350,60, fill="", outline="")
            self.tag_bind(clickAreaSettings, '<Button-1>',lambda event: controller.show_frame(Pin))
        else:
            clickAreaBack = self.create_rectangle(0,0,350,60, fill="", outline="")
            self.tag_bind(clickAreaBack,'<Button-1>', lambda event: controller.show_frame(Ubersicht)) 

        clickAreaBR167 = self.create_rectangle(0,60,350,315, fill="", outline="")
        clickAreaBR213 = self.create_rectangle(0,316,350,570, fill="", outline="")
        clickAreaStar3 = self.create_rectangle(0,571,350,825, fill="", outline="")
        clickAreaTelematik = self.create_rectangle(0,826,350,1080, fill="", outline="")
        self.tag_bind(clickAreaBR167,'<Button-1>', lambda event: controller.show_frame(BR167))
        self.tag_bind(clickAreaBR213,'<Button-1>', lambda event: controller.show_frame(BR213))
        self.tag_bind(clickAreaStar3,'<Button-1>', lambda event: controller.show_frame(Star3))
        self.tag_bind(clickAreaTelematik,'<Button-1>', lambda event: controller.show_frame(Telematik))
       
app = Main(vollbild=False)
app.mainloop
从tkinter导入*
从DataSQL导入*
主类(Tk):
定义初始化(self,vollbild=False):
打印(“主初始化”)
Tk.uuuu init_uuuuuuuuuu(自我)#最初的名字是什么
传统几何学(self,(“1920x1080”)#setzen von verschiedenen Parametern für das Fenster
传统头衔(自我,简称“劳工”)
Tk.wm_overrideredirect(自、自拍)
容器=框架(自身)#框架“容器”与本征对象(也是主芬斯特)之间
容器。包装(side=“top”,fill=“both”,expand=True)#框架和框架的平台
container.grid_rowconfigure(0,weight=1)#Platzieren im grid
container.grid_column配置(0,权重=1)#Platzieren im grid
self.frames={}Erstellt-leere-Liste
对于F in(Ubersicht、设置、Pin、BR167、BR213、Star3、Telematik):
框架=F(容器,自身)#对象框架与Klassen框架(框架结构zB“Übersicht”)之间的关系
self.frames[F]=frames#Objekte werden in der Liste gespeichert,unter dem Namen der Klasse(zB“frames[bersicht]”)
frame.grid(row=0,column=0,sticky=“nsew”)#Platzieren des Frames im grid,wobei das grid aus nur einem Feld besteht,wird nur für die Funktionalität benötigt
自我展示框架(Ubersicht)#Zeigt immer dieÜBersichtseite bei启动
#打印(自帧)
def show_frame(self,cnt):#方法是使用框架和somit-umschalten-zwischen“标签”
帧=自身帧[cnt]
frame.tkraise()
打印(“框架升高”,cnt)
Ubersicht类(框架):
定义初始化(自、父、控制器):
打印(“Ubersicht初始化”)
帧。\uuuu初始化(自,父)
self.interfaceImage=PhotoImage(文件=“/home/pi/Documents/program/labourueberwachung3/IMG 1080/Übersicht.png”)
canvUbersicht=canv(self,controller,img=self.interface图像,Uber=1)
self.\uu eventExit=threading.Event()
self.\u thread=threading.thread(target=self,args=(canvUbersicht,self.\u eventExit,)
self.\uuu thread.start()
定义呼叫(自我、canvUbersicht、停止事件):
而不是停止事件。请等待(1):
canvUbersicht.create_text(500500,text=“HEY”)
canv类(画布):
def u u init u;(self、parent、controller、img=None、Uber=None):
画布。\uuuuu初始化(自,父)
打印(“画布初始化”)
self.config(宽度=1920,高度=1080)
self.place(x=0,y=0)
如果(img!=无):
self.create_image(0,0,锚点=NW,image=img)
如果(Uber==1):
单击AreaSettings=self。创建矩形(0,0350,60,fill=“”,outline=“”)
self.tag\u bind(单击区域设置,,,lambda事件:控制器。显示帧(Pin))
其他:
单击AreaBack=self。创建一个矩形(0,0350,60,fill=“”,outline=“”)
self.tag\u bind(单击AreaBack',lambda事件:controller.show\u frame(Ubersicht))
单击区域BR167=self。创建矩形(0,60350315,fill=”“,outline=”“)
单击区域BR213=self。创建矩形(0316350570,fill=“”,outline=“”)
单击AreaStar3=self。创建\u矩形(0571350825,fill=“”,outline=“”)
单击AreaTelematik=self。创建_矩形(08263501080,fill=“”,outline=“”)
self.tag_bind(单击区域BR167',lambda事件:controller.show_frame(BR167))
self.tag\u bind(单击区域BR213',lambda事件:controller.show\u frame(BR213))
self.tag\u bind(单击区域Star3',lambda事件:controller.show\u frame(Star3))
self.tag_bind(单击AreaTelematik',lambda事件:controller.show_frame(Telematik))
app=Main(vollbild=False)
app.mainloop
我的mainloop/mainthread从哪里开始,在哪里结束

主线程是您在另一个线程中没有显式调用的所有代码

Tkinter是单线程的,对小部件的所有访问都必须来自同一个线程。当您执行
self.\uu thread=threading.thread(target=self,…)
时,会导致一些Tkinter代码在另一个线程中运行


您需要重写应用程序,以便数据收集在一个单独的线程中,该线程通过线程安全队列与主GUI线程通信。您可以从线程推送队列上的信息,GUI线程可以轮询队列。

可能线程尝试在
mainloop()之前使用tkinter元素
启动并创建它们。可以尝试在线程中使用
sleep()
,以便