Reputation: 11
I'm mucking about with Tkinter and Python. I have a basic gui with a couple of buttons on, one button goes away and does something that takes some amount of time, which is variable. The problem is when I hit this button the whole of my gui locks up/ doesnt show correctly - I guess because its trying to do these things that take some amount of time and its blocking the gui.
I have looked into threading and queues, but I can't figure it out. I think I need to fire off my lookup method on a thread and then queue the results as they come back and update the listbox as there coming back?
I'm on windows if this makes a difference to the way I use threads.
Kind Regards
david
Basic code below.
class Search:
def __init__(self, master):
self.seeds = []
frame = Frame(master, width=700, height=500)
frame.pack_propagate(0)
frame.pack(expand=YES, fill=BOTH)
#
# Search results
#
l2 = Label(frame, text="results")
l2.pack(anchor=W)
self.resultfield = Listbox(frame, selectmode=BROWSE)
self.resultfield.grid(row=3, column=1, sticky=N+W+S+E, columnspan=3)
self.resultfield.pack(fill=BOTH)
frame1 = Frame(frame)
frame1.pack()
# Button to action the search
self.getSearchbut = Button(frame1, text="Do Search", command=self.getSearch)
self.getSearchbut.grid(row=1, column=2)
self.getSearchbut.pack()
def getSearch(self):
sa = SearchApi(self.seeds)
results = sa.lookup(self)
for result in results:
self.resultfield.insert(END, user)
def putCSV(self):
print "put the csv files"
class SearchApi:
def __init__(self, seeds):
self.seeds = seeds
def lookup(self):
results = []
# I do something here that takes a while
return results
if __name__ == "__main__":
root = Tk()
root.title("Search")
app = Search(root)
root.mainloop()
Upvotes: 1
Views: 3033
Reputation: 43136
Using threads is simple, really. All you have to do is to import the Thread class:
from threading import Thread
and change the getSearch function to look like this:
def getSearch(self):
t= Thread(target=self.search)#this should work, in case it doesn't, try "t= Thread(target=Search.getSearch,args=[self])" instead.
t.start()
def search(self):
sa = SearchApi(self.seeds)
results = sa.lookup(self)
for result in results:
self.resultfield.insert(END, user)
That should be all you need to do, since I'm pretty sure Tkinter is thread safe. In case it isn't, you'll have to make one thread that inserts the other thread's results into the text widget.
Also, this is Python. It doesn't matter if you're on windows or not :D
Upvotes: 5
Reputation: 114
I had this same issue until just today! Your issue is that the mainloop of Tkinter is interfering with your task loop. I had to take all classes out of my program and use only functions. The button you use will toggle a variable which then starts up the loop task.
Then solution is simple, after about a week of looking (this is a condensed version of my code):
scnBtn = Button(Frame, text="Update", command=readIt)
scnBtn.pack()
def readIt(): ## this is the variable the button changes
global read
read = 1
TK.after(0, readFile) ##this is how you make sure the GUI doesn't freeze up
def readFile(): ## this is the task you want the button to do
global read
if read == 1:
"your task"
if "task is over"
read = 0
if read == 1:
TK.after(0, readFile) ## this will keep the task going until its done.
Hope this helped!
Upvotes: 2