0

I am creating a program that runs multiple threads where each thread updates a variable and then displays that value using tkinter.

The only problem is that I get a RuntimeError whenever I try and update the display:

Exception in thread Thread-x:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 916, in _bootstrap_inner
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/threading.py", line 864, in run
    self._target(*self._args, **self._kwargs)
  File "program.py", line 15, in body
    update()
  File "program.py", line 11, in update
    display.config({"text" : "x = {0}".format(x)})
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 1479, in configure
    return self._configure('configure', cnf, kw)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/tkinter/__init__.py", line 1470, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
RuntimeError: main thread is not in main loop


Some of the solutions I have tried to fix the error are:

  • Make the display object global to the function (using global)
  • Create a seperate function to update the display

However, none of these solutions worked (the RuntimeError still kept occurring).

Below is my program:

import tkinter, time, threading

window = tkinter.Tk()
x = 0
display = tkinter.Label(window)
display.pack()

def update():
    global x
    x += 1
    display.config({"text" : "x = {0}".format(x)}) #It says the error is on this line

def body():
    time.sleep(3)
    update()
    body()

def start_threads():
    for i in range(5):
        thread = threading.Thread(target=body)
        thread.start(); thread.join()

start = tkinter.Button(window, text="Start", command=start_threads)
start.pack()

I do not know how to fix the RuntimeError, so any help with that would be appreciated.

0

2 Answers 2

1

This is actually due to your sleep function, this freezes the main thread for tkinter which you cannot do.

Here's some code that will work:

import tkinter

x = 0
repeat = 0

def start_counter():
    global x, repeat
    repeat+=1
    x += 1
    display.config({"text" : "x = {0}".format(x)})

    if repeat < 5:
        #3000 because 1000 in a second
        window.after(3000, start_counter)


window = tkinter.Tk()
display = tkinter.Label(window)
display.pack()
start = tkinter.Button(window, text="Start", command=start_counter)
start.pack()
window.mainloop()

Notice how I use "window.after(3000, function)". This tells tkinter to do something after 3 seconds and thus doesn't freeze the main thread. If you want it to sleep before even showing the number 1, you need to change a few things, in which case I'd be happy to update my code for you :)

Sign up to request clarification or add additional context in comments.

2 Comments

Please note that I want to use the threading library, as indicated in the question. But still, I'll take the window.after(3000, function) idea into consideration.
I know this because of personal experience, you can use threading but sleep() causes issues unfortunately because of the way Tkinter was built.
0

After a bit of experimentation and the idea suggested by Piero Bird, I have come up this solution:

import tkinter, threading


def start_counter():

    for i in range(1):
         bot = threading.Thread(target=add_one)
         bot.start(); bot.join()
    temp_window = tkinter.Tk()
    temp_window.withdraw()
    window.after(100, start_counter)

def add_one():
    global count
    count += 1

if __name__ == "__main__":
    temp = 0
    count = 0
    window = tkinter.Tk()
    window.minsize(width=500, height=500)
    display = tkinter.Label(window)
    display.pack()
    start = tkinter.Button(window, text="Start", command=start_counter)
    start.pack()

    def update():
        global temp, first
        if count != temp:
            display.config({"text":"x = {0}".format(count)})
            temp = count

        window.after(1, update)


    window.after(1, update)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.