简体   繁体   English

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

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

I'm working on an "multilayered" GUI for my company to monitor temperature and status. 我正在为公司使用“多层” GUI来监视温度和状态。 Because I'm quite new to the python programming, I could use some help with my code. 因为我是python编程的新手,所以可以在代码中使用一些帮助。

Quick code explanation: 快速代码说明:

The code is structured by classes. 该代码由类构成。 The "Main" inits the main window (tkinter) and creates the other frames to display if wanted. “主”将打开主窗口(tkinter),并创建其他要显示的框架。 Every other class, except "canvas", is a frame which will display different things. 除“画布”外,其他所有类别都是一个框架,它将显示不同的内容。

The canvas in each contains an image and some text/variable text. 每个画布包含一个图像和一些文本/可变文本。 A thread is used to get data from a database and change the text in the canvas. 线程用于从数据库获取数据并更改画布中的文本。

The Problem: 问题:

Every time, the thread accessed the canvas and tries to change the text or create an new one, the error "main thread is not in main loop" is thrown. 每次线程访问画布并尝试更改文本或创建新的文本时,都会引发错误"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

If I init the thread without calling the canvas (eg "print("hey") ), everything works fine. 如果我在不调用画布的情况下初始化线程(例如"print("hey") ),则一切正常。

Where does my mainloop / mainthread begin and where do they end? 我的mainloop / mainthread在哪里开始,在哪里结束?

I have already read several Questions and rearranged the code / thread, but it won't change anything. 我已经阅读了几个问题并重新排列了代码/线程,但不会改变任何内容。

I would be really happy, if someone could help me. 如果有人可以帮助我,我将非常高兴。

important code: 重要代码:

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

Where does my mainloop / mainthread begin and where do they end? 我的mainloop / mainthread在哪里开始,在哪里结束?

The main thread is all the code that you don't explicitly call in another thread. 主线程是您没有在另一个线程中显式调用的所有代码。

Tkinter is single-threaded, and all access to widgets must be from the same thread. Tkinter是单线程的,对窗口小部件的所有访问都必须来自同一线程。 When you do self.__thread = threading.Thread(target=self, ...) you are causing some tkinter code to run in another thread. 当您执行self.__thread = threading.Thread(target=self, ...) ,会导致某些tkinter代码在另一个线程中运行。

You will need to rewrite your application so that the data gathering is in a separate thread which communicates with the main GUI thread via a thread-safe queue. 您将需要重新编写应用程序,以便数据收集位于单独的线程中,该线程通过线程安全队列与主GUI线程进行通信。 You can push information on the queue from the thread, and the gui thread can poll the queue. 您可以从线程将信息推送到队列中,而gui线程可以轮询队列。

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

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