Problem with python multithreaded app with gui based on Tkinter

Hi. I’m working on small app which will be measuring and showing the value in real time. Now it’s simulated, but that’s not the point. The app is here: https://github.com/MaciejKamianowski/python_gui_multithread_app/blob/master/threading_example_with_app_gui.py

And I can start measuring loop and make new thread with the button ,Rozpocznij pomiary" and stop it with ,Koniec pomiarów" button. But I would like to continue that loop by clicking the ,Rozpocznij pomiary" button again. But in that situation it throws an exception:

Exception in Tkinter callback
Traceback (most recent call last):
File “C:\Users\user1\Anaconda3\lib\tkinter__init__.py”, line 1705, in __call__
return self.func(*args)
File “G:/PythonProjects/threading_example_with_app_gui.py”, line 36, in buttonStartClicked
t.start()
File “C:\Users\user1\Anaconda3\lib\threading.py”, line 843, in start
raise RuntimeError(“threads can only be started once”)
RuntimeError: threads can only be started once

Do you have any idea how to deal with it? I’m currently new to the threads in python so please let me understand it better.

I’m not entirely sure I understand your code, having never used Tkinter, but perhaps you could get your desired behavior if instead of:

while getattr(t, "do_run", True):
    measure()
    time.sleep(1)

you instead did:

while True:
    if getattr(t, "do_run", True):
        measure()
    time.sleep(1)

Then your “pause” would simply not call your measure function. Your thread would only sleep, and you wouldn’t have to deal with starting and terminating new threads.

1 Like

When you called

t.join()

the program waited until thread t died. As the error message states, you can’t re-start a thread. 

So you can try the approach suggested by @cleancut  or you can create a new thread. I’m not sure if I’ve got this right, but you might rewrite this:

t = threading.Thread(target=doit_measure, args=("task",))
def buttonStartClicked():
    print("The START button was clicked!")
    if not t.is_alive():
        t.start()

to something like this:

def buttonStartClicked():
    print("The START button was clicked!")
    t = threading.Thread(target=doit_measure, args=("task",))
    t.start()

What you’ll need to do is insure that the ‘stop’ button was clicked before allowing the start button to create a new thread (e.g. you press ‘start’, then press ‘start’ again).