I'm having issues passing variables between two scripts in python without ending the imported script. I would like for the status bar in my tkinter GUI to update to reflect what number the counter in script2
is on. I've included the code below:
from tkinter import *
import script2
root = Tk()
canvas = Canvas(root, width=300, height=300)
canvas.pack()
def runScript():
var = script2.information()
button1 = Button(root, text="Click Me!", command=runScript)
button1.pack()
var = StringVar()
var.set('Waiting for Input...')
status = Label(root, textvariable=var, bd=1, relief=SUNKEN, anchor=W)
status.pack(side=BOTTOM, fill=X)
root.mainloop()
script2.py
would be:
#script2
import time
def information():
variable = 0
while variable < 500:
yield variable
variable += 1
print(variable)
time.sleep(1)
I understand that this has to do with generators, but my understanding was that yield
would pause the loop, send the data to the original program, let it process it, and then un-pause the loop. Is there a better way of understanding this process?
For one thing, script2.information()
is a generator function which means you will have to manually iterate the generator object returned on the first call it to get successive values.
For another, tkinter
doesn't support multithreading. One thing you can do is schedule for a function to be called after a certain amount of time using the universal widget method after()
. In this case, it can be used to schedule a call to an (added) function that iterates the generator object after it's been created by calling script2.information()
and updates the StringVar()
widget accordingly each time it's called.
You also need to change script2.py
so it doesn't call time.sleep()
. Doing so will make your tkinter GUI program hang whenever it's called (since it temporarily interrupts execution of the tkinter mainloop()
).
Modified script2.py
:
import time
def information():
variable = 0
while variable < 60: # changed from 500 for testing
yield variable
variable += 1
print(variable)
# time.sleep(1) # don't call in tkinter programs
main script:
from tkinter import *
import script2
DELAY = 100 # in millisecs
root = Tk()
canvas = Canvas(root, width=300, height=300)
canvas.pack()
def do_update(gen, var):
try:
next_value = next(gen)
except StopIteration:
var.set('Done!')
else:
var.set(next_value)
root.after(DELAY, do_update, gen, var) # call again after delay
def run_script(var):
gen = script2.information() # create generator object
do_update(gen, var) # start iterating generator and updating var
var = StringVar()
var.set('Waiting for Input...')
button1 = Button(root, text="Run script!", command=lambda: run_script(var))
button1.pack()
status = Label(root, textvariable=var, bd=1, relief=SUNKEN, anchor=W)
status.pack(side=BOTTOM, fill=X)
root.mainloop()