Reputation: 14096
I have a basic python class that creates a window using the standard Tkinter
library:
import Tkinter
class GUI(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def lock_func(self):
while 1==1:
print "blah"
def initialize(self):
self.processBtn = Tkinter.Button(self, text="Process", command=self.lock_func)
self.processBtn.pack()
app = GUI(None)
app.mainloop()
when I hit the Process
button, the window doesn't respond.
I want to be able to close the program (using the x button) whene the lock_func
is runing.
Upvotes: 6
Views: 6591
Reputation: 17532
One way is to use threading:
import Tkinter
import thread
class GUI(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def lock_func(self):
while 1==1:
print "blah"
def initialize(self):
self.processBtn = Tkinter.Button(self, text="Process", command=lambda: thread.start_new_thread(self.lock_func, ()))
self.processBtn.pack()
app = GUI(None)
app.mainloop()
However, it will keep printing until you close the Python console.
To stop it, you can use another button that changes a variable:
import Tkinter
import thread
class GUI(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.shouldPrint = True
self.initialize()
def lock_func(self):
while self.shouldPrint:
print "blah"
def setShouldPrint(self, value):
self.shouldPrint = value
def initialize(self):
self.processBtn = Tkinter.Button(self, text="Process", command=lambda: thread.start_new_thread(self.lock_func, ()))
self.stopBtn = Tkinter.Button(self, text = "Stop", command = lambda: self.setShouldPrint(False))
self.processBtn.grid(row = 1)
self.stopBtn.grid(row = 2)
app = GUI(None)
app.mainloop()
Upvotes: 0
Reputation: 879471
You could use a generator to hold the state within the loop, and use yield
to relinquish control back to the main loop. Then use self.after to repeatedly call the generator's next
method to simulate the effect of while True
-- but doing it in a way which is friendly to Tkinter's main loop.
import Tkinter as tk
class App(object):
def __init__(self, master):
self.master = master
self.initialize()
def lock_func(self):
def step():
while True:
print("blah")
self.nextstep_id = self.master.after(1, nextstep)
yield
nextstep = step().next
self.nextstep_id = self.master.after(1, nextstep)
def stop(self):
self.master.after_cancel(self.nextstep_id)
print("stopped")
def initialize(self):
self.nextstep_id = 0
self.process_button = tk.Button(self.master, text="Process",
command=self.lock_func)
self.stop_button = tk.Button(self.master, text="Stop",
command=self.stop)
self.process_button.pack()
self.stop_button.pack(expand='yes', fill='x')
root = tk.Tk()
app = App(root)
root.mainloop()
Upvotes: 5
Reputation: 728
You can use the window.update()
method too keep your GUI active and functional after every time you change something on it. During the roots mainloop
, this happens automatically but if you're prolonging the mainloop it's probably a good idea to do it manually your self. Put the window.update()
in the loop that is taking a while. Note: window
is a Tk()
object
Upvotes: 4