"RuntimeError: Calling Tcl from different appartment" tkinter and threading
Asked Answered
C

2

12

I want to implement GUI using threading and tkinter (python 3.6).
When I run GUIExecution.py, the following error occurs.
"RuntimeError: Calling Tcl from different appartment" on self.root.mainloop() in base_gui_class.py
I am implementing it on a class basis, and the three code files are as follows.
The executable file is GUIExecution.py. I spent a lot of time trying to fix the error, but I have not been able to fix it yet.
Please give a lot of advice.
Additionally, if I run the following code in a python2 environment, it works fine without error.

GUIExecution.py

from base_gui_class import *

from base_class import *

speed = 1000
height = 500
width = 700

base_model = base_class()
gui = base_gui_class(base_model, speed, height, width)
base_model.visualize()

base_class.py

class base_class():
    genes = []
    dicLocations = {}
    gui = ''
    best = ''
    time = 0

    def __init__(self):
        pass

    def visualize(self):
        if self.gui != '':
            self.gui.start()

    def registerGUI(self, gui):
        self.gui = gui

base_gui_class.py

import threading
import tkinter as tk
import math
import threading
import time
class base_gui_class(threading.Thread):
    root = ''
    canvas = ''
    speed = 0
    base_model = ''
def __init__(self, base_model, speed, h, w):
    threading.Thread.__init__(self)
    self.base_model = base_model
    base_model.registerGUI(self)

    self.root = tk.Tk()

    self.canvas = tk.Canvas(self.root, height=h, width=w)
    self.canvas.pack()

    self.root.title("Test")
    self.speed = 1 / speed
def run(self):
    self.root.mainloop()
def update(self):
    time.sleep(self.speed)
    width = int(self.canvas.cget("width"))
    height = int(self.canvas.cget("height"))
    self.canvas.create_rectangle(0, 0, width, height, fill='white')
def stop(self):
    self.root.quit()
Cucumber answered 21/8, 2017 at 14:3 Comment(0)
R
26

To a very good first and second approximation, the core of Tk is single threaded. It can be used from multiple threads, but only by initialising it separately in each of those threads. Internally, it uses thread-specific variables extensively to avoid the need for major locking (that is, it has nothing like a big Global Interpreter Lock) but that means you must not cheat. Whatever thread initialises a Tk context must be the only thread that interacts with that Tk context. This includes loading the Tkinter module so you are effectively restricted to using Tkinter from your main thread only; working around this is serious expert's-only stuff.

I recommend that you make your worker threads make changes to your GUI by posting events to it using a queue (or otherwise interlock with critical sections and condition variables, though I find queues easier in practice).

Remedial answered 21/8, 2017 at 19:0 Comment(0)
B
2

pip install tkthread

#call the function which shows error like this:

tkthread.call_nosync(yourfunction)

this tkthread library handles all the threading internally by itself.

I recommend you reading the documentation of this library:https://pypi.org/project/tkthread/ .

Breadwinner answered 13/10, 2022 at 13:41 Comment(1)
Answer will look better when using markdown rules - stackoverflow.com/editing-helpAnaphrodisiac

© 2022 - 2024 — McMap. All rights reserved.