M.M*_*hel 5 python multithreading canvas tkinter
我正在为我的公司开发一个“多层”GUI 来监控温度和状态。因为我对 python 编程很陌生,所以我可以在我的代码中使用一些帮助。
\n代码由类构成。“Main”初始化主窗口(tkinter)并创建其他要显示的框架(如果需要)。除“canvas”之外的所有其他类都是一个将显示不同内容的框架。
\n每个中的画布都包含图像和一些文本/变量文本。\n线程用于从数据库获取数据并更改画布中的文本。
\n每次,线程访问画布并尝试更改文本或创建新文本时,"main thread is not in main loop"都会引发错误。
Exception in thread Thread-1:\nTraceback (most recent call last):\n File "/usr/lib/python3.4/threading.py", line 920, in _bootstrap_inner\n self.run()\n File "/usr/lib/python3.4/threading.py", line 868, in run\n self._target(*self._args, **self._kwargs)\n File "/home/pi/Documents/Programme/MM/TEST_Dateien/TEST_QUEUE.py", line 154, in __call__\n canvUbersicht.create_text(500,500, text="HOIIIIII")\n File "/usr/lib/python3.4/tkinter/__init__.py", line 2345, in create_text\n return self._create('text', args, kw)\n File "/usr/lib/python3.4/tkinter/__init__.py", line 2321, in _create\n *(args + self._options(cnf, kw))))\nRuntimeError: main thread is not in main loop\nRun Code Online (Sandbox Code Playgroud)\n如果我在不调用画布的情况下初始化线程(例如"print("hey")),则一切正常。
我的主循环/主线程从哪里开始以及在哪里结束?
\n我已经阅读了几个问题并重新排列了代码/线程,但它不会改变任何东西。
\n如果有人能帮助我,我会非常高兴。
\n重要代码:
\nfrom tkinter import*\nfrom DataSQL import*\n\nclass Main(Tk):\n def __init__(self, vollbild=False):\n print("Main INIT")\n Tk.__init__(self) #Initialisieren von Tkinter und somit erzeugen des Fensters\n Tk.geometry(self, ("1920x1080")) #setzen von verschiedenen Parametern f\xc3\xbcr das Fenster\n Tk.title(self, ("Labor\xc3\xbcberwachung"))\n Tk.wm_overrideredirect(self, vollbild)\n\n container = Frame(self) #Frame "container" wird im eigenen Objekt(also main fenster) erstellt\n container.pack(side="top",fill="both",expand=True) #Platzieren des Frames und ausf\xc3\xbcllen des ganzen Fensters\n container.grid_rowconfigure(0, weight=1) #Platzieren im Grid\n container.grid_columnconfigure(0, weight=1) #Platzieren im Grid\n \n self.frames = {} #Erstellt leere Liste\n \n for F in (Ubersicht, Settings, Pin, BR167, BR213, Star3, Telematik):\n frame = F(container, self) #Objekt frame wird erzeugt durch aufruf von Konstruktoren der Klassen(Frameklassen zB "\xc3\x9cbersicht")\n self.frames[F] = frame #Objekte werden in der Liste gespeichert, unter dem Namen der Klasse(zB "frames[\xc3\x9cbersicht]")\n frame.grid(row=0, column=0, sticky="nsew") #Platzieren des Frames im Grid, wobei das Grid aus nur einem Feld besteht, wird nur f\xc3\xbcr die Funktionalit\xc3\xa4t ben\xc3\xb6tigt\n\n self.show_frame(Ubersicht) #Zeigt immer die \xc3\x9cbersichtsseite bei StartUp\n #print(self.frames)\n\n def show_frame(self, cnt): #Methode zum Framewechsel und somit umschalten zwischen 'Tabs'\n frame = self.frames[cnt]\n frame.tkraise()\n print("frame raised",cnt)\n\n\nclass Ubersicht(Frame):\n\n def __init__(self, parent, controller):\n print("Ubersicht INIT")\n Frame.__init__(self, parent)\n \n self.interfaceImage = PhotoImage(file="/home/pi/Documents/Programme/Laborueberwachung3/IMG 1080/\xc3\x9cbersicht.png")\n canvUbersicht = canv(self, controller, img=self.interfaceImage, Uber=1)\n \n self.__eventExit = threading.Event()\n self.__thread = threading.Thread(target=self, args=(canvUbersicht, self.__eventExit,))\n self.__thread.start()\n \n def __call__(self,canvUbersicht,stop_event):\n while not stop_event.wait(1):\n canvUbersicht.create_text(500,500,text="HEY")\n\nclass canv(Canvas):\n def __init__(self, parent, controller, img=None, Uber=None):\n Canvas.__init__(self, parent)\n print("canvas INIT")\n self.config(width=1920,height=1080)\n self.place(x=0,y=0)\n if (img != None):\n self.create_image(0,0,anchor=NW,image=img)\n \n if (Uber == 1):\n clickAreaSettings = self.create_rectangle(0,0,350,60, fill="", outline="")\n self.tag_bind(clickAreaSettings, '<Button-1>',lambda event: controller.show_frame(Pin))\n else:\n clickAreaBack = self.create_rectangle(0,0,350,60, fill="", outline="")\n self.tag_bind(clickAreaBack,'<Button-1>', lambda event: controller.show_frame(Ubersicht)) \n\n clickAreaBR167 = self.create_rectangle(0,60,350,315, fill="", outline="")\n clickAreaBR213 = self.create_rectangle(0,316,350,570, fill="", outline="")\n clickAreaStar3 = self.create_rectangle(0,571,350,825, fill="", outline="")\n clickAreaTelematik = self.create_rectangle(0,826,350,1080, fill="", outline="")\n self.tag_bind(clickAreaBR167,'<Button-1>', lambda event: controller.show_frame(BR167))\n self.tag_bind(clickAreaBR213,'<Button-1>', lambda event: controller.show_frame(BR213))\n self.tag_bind(clickAreaStar3,'<Button-1>', lambda event: controller.show_frame(Star3))\n self.tag_bind(clickAreaTelematik,'<Button-1>', lambda event: controller.show_frame(Telematik))\n \napp = Main(vollbild=False)\napp.mainloop\nRun Code Online (Sandbox Code Playgroud)\n
我的主循环/主线程从哪里开始以及在哪里结束?
主线程是您在另一个线程中未显式调用的所有代码。
Tkinter 是单线程的,对小部件的所有访问都必须来自同一线程。当你这样做时,self.__thread = threading.Thread(target=self, ...)你会导致一些 tkinter 代码在另一个线程中运行。
您需要重写应用程序,以便数据收集位于单独的线程中,该线程通过线程安全队列与主 GUI 线程进行通信。您可以从线程中推送队列上的信息,并且 gui 线程可以轮询队列。