0

I'm trying to make tkinter program to wait in the middle of the function execution, wait until variable is changed in separate thread and then proceed. The code provided is not actual task, it's my attempts to understand wait_variable and make it work at least in some way.

The task itself is actually this: I'm trying to make my code wait until windows service status is changed and then proceed. So I used this code and I need to wait until status changes.

Here is the code I wrote while trying to make it work:

import time
import tkinter as tk

from threading import Thread
from tkinter import messagebox


def test():
    my_var = tk.IntVar()
    my_var.set(1)

    label_2 = tk.Label(textvariable=my_var)
    label_2.pack()

    def wait_for_var():
        nonlocal my_var
        for i in range(5):
            label.config(text='iteration {}'.format(i))
            time.sleep(1)
            my_var.set(1)
        my_var.set(2)

    Thread(target=wait_for_var).start()
    while my_var.get() != 2:
        root.wait_variable('my_var')
        messagebox.showinfo('aha!', 'my_var changed!')
    messagebox.showinfo('done!', 'done!')


root = tk.Tk()
root.geometry('800x600')

text = 'init'

label = tk.Label(text='init')
label.pack()

btn = tk.Button(text='click me', command=test)
btn.pack()

root.mainloop()

I expected program to exit while loop when my_var changes it's value to 2. But for some reason it's stuck there forever and it seems to not exit wait_variable even after main window closed. I stumbled upon this and this question about it, but I think that's still not the case. The problem at those questions was in variable not changing. In my code my_var is actually changing and it can be seen in second label. But further execution never happens. As wait_variable description claims: "setting it to it’s current value also counts". So it means, that after each iteration inside second thread, when it's reassigned to the same value - first messagebox should show up. And after my_var value changes to 2, - second messagebox should show up. But they never do.

What am I missing here?

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80

1 Answers1

1

In order to have my_var work as intended, you must change your call to root.wait_variable from:

root.wait_variable('my_var')

to

root.wait_variable(my_var)

Other than that, you probably need to put the logic of terminating the thread inside the tread itself, or it will continue its iteration until it is done.

Reblochon Masque
  • 35,405
  • 10
  • 55
  • 80
  • Thank you so much! Looks logical and I checked description for `wait_variable` again and it doesn't mension string anywhere, so now it seems stupid why did I use quotes. ) – Constantine Ketskalo Jul 03 '19 at 07:43
  • Why do you think I need to change the logic of terminating? Because of potential eternal loop? You mean timeout? – Constantine Ketskalo Jul 03 '19 at 07:45
  • You are welcome - I am not well versed with `threads`, but unless some sort of termination signal emanates from within the thread I don't know how you will tell it that it can terminate; maybe there is a way, IDK. – Reblochon Masque Jul 03 '19 at 08:20
  • 1
    Actually that's good point and usually I double check to avoid eternal loops. It's just I thought about not doing it here, because this code here is just some experimenting and actual thing that I was coding is check if windows service's status is 'running' or 'stopped'. If not (means it's in process of starting or stopping), then just wait till that process finishes and then continue. So doesn't seem to have much sence to include timeout here, but I guess it's still good to add one just in case. Which I did: not gonna harm, ha? ;) Thanks. – Constantine Ketskalo Jul 04 '19 at 06:35