簡體   English   中英

python | tkinter和線程:“主線程不在主循環中”

[英]python | tkinter and threading: “main thread is not in main loop”

我正在為公司使用“多層” GUI來監視溫度和狀態。 因為我是python編程的新手,所以可以在代碼中使用一些幫助。

快速代碼說明:

該代碼由類構成。 “主”將打開主窗口(tkinter),並創建其他要顯示的框架。 除“畫布”外,其他所有類別都是一個框架,它將顯示不同的內容。

每個畫布包含一個圖像和一些文本/可變文本。 線程用於從數據庫獲取數據並更改畫布中的文本。

問題:

每次線程訪問畫布並嘗試更改文本或創建新的文本時,都會引發錯誤"main thread is not in main loop"

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

我的mainloop / mainthread在哪里開始,在哪里結束?

主線程是您沒有在另一個線程中顯式調用的所有代碼。

Tkinter是單線程的,對窗口小部件的所有訪問都必須來自同一線程。 當您執行self.__thread = threading.Thread(target=self, ...) ,會導致某些tkinter代碼在另一個線程中運行。

您將需要重新編寫應用程序,以便數據收集位於單獨的線程中,該線程通過線程安全隊列與主GUI線程進行通信。 您可以從線程將信息推送到隊列中,而gui線程可以輪詢隊列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM