Last active
December 17, 2015 14:08
-
-
Save mikofski/5621839 to your computer and use it in GitHub Desktop.
async Tk waitbox widget
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
An example of a combobox that adds user entries using key binding to return | |
""" | |
from Tkinter import * | |
from ttk import * | |
def on_combobox_selected(event): | |
new_value = event.widget.get() | |
is_in_list = event.widget.current() | |
if is_in_list < 0: | |
event.widget['value'] += (new_value, ) | |
if __name__ == '__main__': | |
root = Tk() | |
master = Frame(root) | |
cbox = Combobox(master, values=['this','that']) | |
cbox.pack(fill=BOTH) | |
master.pack(fill=BOTH) | |
cbox.bind('<Return>', on_combobox_selected) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
An example of a ttk Progressbar that is way better than ticking hourglass in waitbox_widget. | |
Combine this with waitbox_widget as the process on the main thread while the async task | |
completes and it would be a nice addition. It even has a builtin timer! | |
""" | |
from Tkinter import * | |
from ttk import * | |
if __name__ == '__main__': | |
root = Tk() | |
master = Frame(root) | |
master.pack(fill=BOTH) # fill the Tk root window with the Frame | |
Label(master, text="Please wait ...").pack(fill=BOTH) # a custom message, fill the Frame | |
# by default widgets are stacked vertically | |
progbar = Progressbar(master, orient=HORIZONTAL, length='3i', mode='determinate', value=0) | |
# save progbar, you'll need it to change the value | |
progbar.pack(fill=BOTH) # fill the Frame with the progressbar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
An example of a Tix Meter widget that is only slightly nicer than the ticking hourglass | |
in waitbox_widget. It pales in comparison to ttk's Progressbar. | |
""" | |
import Tix | |
if __name__ == '__main__': | |
root = Tix.Tk() | |
master = Tix.Frame(root) | |
progmeter = Tix.Meter(master, fillcolor='blue', text='progress', value=10) | |
progmeter.pack(fill='both') | |
master.pack(fill=BOTH) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
from Tkinter import Frame, Toplevel, IntVar, BOTH | |
from threading import Thread | |
from Queue import Queue | |
# basic logging | |
logging.basicConfig(level=logging.DEBUG, | |
format='[%(levelname)s] (%(threadName)-10s) %(message)s') | |
class WaitWidget(Frame): | |
""" | |
A wait widget that shows something is happening. | |
:parameter queue: A queue into which results and other info are placed. | |
:parameter master: A Toplevel Tk window. | |
:returns obj: A WaitWidget object. | |
""" | |
def __init__(self, queue, master): | |
self.queue = queue # the queue | |
Frame.__init__(self, master) # call the Frame constructor | |
self.pack(fill=BOTH) # fill the Toplevel Tk window with the frame | |
self.focus_set() # get focus | |
self.grab_set() # make the window modal | |
master.resizable(False, False) # not resizable | |
master.title("") # no title | |
# don't let user close window using X - instead call timer | |
master.protocol("WM_DELETE_WINDOW", self.timer) | |
# Customize with whatever info is put in the queue, EG: with "progress" | |
# create a integer variable in master called "wait" | |
self.wait = IntVar(master, 0, "wait") | |
# put an hourglass in the widget and display how long we've been waiting | |
Label(master, bitmap="hourglass").pack(fill=BOTH) # customize with a photoimage, | |
Label(master, text="Please wait ...").pack(fill=BOTH) # a custom message | |
Label(master, textvariable=self.wait).pack(fill=BOTH) # and custom output | |
# start timer | |
self.timer() # customize with a callback | |
def timer(self): | |
""" | |
A callback that counts milliseconds until `self.queue` has somthing in it | |
""" | |
wait = self.wait.get() + 1 # increment 100[ms] | |
# customize with a different action based on queue contents | |
# For example: | |
# >>> result = self.queue.get() | |
# >>> if type(result) == int: | |
# >>> self.wait.set(result) | |
# >>> else: | |
# >>> self.queue.put(result) | |
# >>> self.quit() | |
if not self.queue.empty(): | |
# when queue is filled, quit loop and print elapsed time | |
print 'elapsed time = %2.1f [s]' % (wait * 0.10) | |
self.quit() | |
self.wait.set(wait) | |
# loop over this callback every 100[ms] until queue is filled | |
# this does **not** block the main thread, yay! | |
self.after(100, self.timer) | |
def setqueue(original_function, queue): | |
""" | |
Create a new function `queuefun` that calculates the results from the | |
`original_function` and puts them in a queue. | |
:parameter original_function: The function from which the results are added to \ | |
the queue. | |
:parameter queue: The queue to which the results of the original_function are \ | |
added. | |
:returns queuefun: The new function. | |
""" | |
def queuefun(*args, **kwargs): | |
""" | |
Call `original_function` with args & kwargs and put the results in `queue`. | |
NOTE: this is function *call*, not a function object! | |
This is equivalent to: | |
>>> results = original_function(*args, **kwargs) # calc results | |
>>> queue.put(results) # put results in queue | |
>>> results = queue.get() # get results from queue | |
""" | |
logging.debug('Starting') | |
queue.put(original_function(*args, **kwargs)) | |
logging.debug('Exiting') | |
return queuefun | |
def waitbox(original_function): | |
""" | |
Create a new function that adds a waitbox widget to original_function. | |
:parameter original_function: A funciton to wrap with a waitbox waitWidget | |
""" | |
def new_function(*args, **kwargs): | |
""" | |
Create a queue, create a queuefun from original_function and make the | |
new queuefun the target of a thread, passing the thread target | |
original_function's args and kwargs. Then instantiate a new Tk Toplevel | |
Frame called master and a new waitWidget with the queue and master. | |
Start master's mainloop which exits when the original_function's | |
results are fed to the queue. Destroy master and return the | |
original_function's results. | |
""" | |
queue = Queue.Queue() # create a queue | |
queuefun = setqueue(original_function, queue) # create a queuefun function | |
thread = Thread(target=queuefun, args=args, kwargs=kwargs) # create thread | |
thread.start() # start the thread | |
master = Toplevel() # make a Toplevel Tk window | |
waitBox = WaitWidget(queue, master) # create a WaitWidget object | |
waitBox.mainloop() # start its mainloop and wait for it to end | |
master.destroy() # kill the WaitWidget | |
return queue.get() # return the final contents of the queue | |
return new_function |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment