Wednesday, January 13, 2016

Python Tkinter progress bar

Progress bars are super easy in Tkinter, and there are two flavors. The regular kind is a bar that expands from left to right based on setting the object's "value" with respect to its "maxvalue". That is called a "determinate" progress bar. There is also an "indeterminate" progress bar that has a section that bounces back and forth from end to end to show general aliveness of a task. With an indeterminate progress bar, you can just call it's start() and stop() functions, or use a more direct method of showing aliveness by inserting step() commands in the code (.step accepts a percent value from 0 to 100). Some links:

http://stackoverflow.com/questions/7310511/how-to-create-downloading-progress-bar-in-ttk

https://gist.github.com/livibetter/6850443

The default Windows progress bar was pretty nasty looking, especially the indeterminate one which had a very thin indicator. It turns out that the way to change this is to define a ttk progressbar "style," which allows the programmer to chose from a handful of named styles, and then set colors for components. There's a command that you can do in a python console to get a list of available styles on whatever OS you're working in. Some are available on most platforms, others might be specific to whatever platform you're on. Some commentators to some forum threads that I checked out seemed to love the "clam" style, I preferred "classic" because it was big and blocky and with that name I was sure to find it on both Windows and Linux platforms. Some links about styles:

This shows how to use the theme_names() function of a Style object to get a list of additional styles. I can't see how you'd want to use this more than once, unless you were writing some really fancy code. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-theme-layer.html

Here is the examples showing how to change the progressbar color, and the first example of using Style that I found. For some reason this guy thinks that "clam" is good looking style: http://stackoverflow.com/questions/13510882/how-to-change-ttk-progressbar-color-in-python

The man page for Style: https://docs.python.org/3/library/tkinter.ttk.html#tkinter.ttk.Style

Some solutions to trying to change the appearance of the progress bar. I solved my problem by just picking a different theme. This post proposes a torturous use of a canvas, while the second says to use a Style that allows for size adjustment. http://stackoverflow.com/questions/17912624/ttk-progressbar-how-to-change-thickness-of-a-horizontal-bar

Here's a man page for Progressbar that mentions that they have a Style option: https://www.tcl.tk/man/tcl/TkCmd/ttk_progressbar.htm

Here's a link that mentions somebody having a problem with their progressbar. The issue however was that the programmer wasn't properly making his code event-driven. http://stackoverflow.com/questions/16400533/why-ttk-progressbar-appears-after-process-in-tkinter

A nice man page for Progressbar that helped show the three methods that indeterminate progressbars have, start(), stop(), and step(). In the end, I found it helpful to just use the step() function for my indeterminate progressbar from my code rather than let it run on its own with start() and stop()
http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk-Progressbar.html



My init code for drawing the progress bars on my gui:

import Tkinter, ttk

class MyGui(self, *args, **kwargs):
def __init__(self, *args, **kwargs):
Tkinter.Tk.__init__(self, *args, **kwargs)

self.title('My GUI')

s = ttk.Style()
s.theme_use('classic')
s.configure("blue.Horizontal.TProgressbar", foreground='blue', background='blue')

f = Tkinter.Frame(self)

self.aliveness = ttk.Progressbar(f, style="blue.Horizontal.Tprogressbar", orient="horizontal", length=600, mode="indeterminate")
self.aliveness.pack(padx=10,pady=10)

self.progress = ttk.Progressbar(f, style="blue.Horizontal.Tprogressbar", orient="horizontal", length=600, mode="determinate")
self.progress["value"] = 0
self.progress["maximum"] = 100 ## Note, not strictly necessary. If not specified 100 is assumed
self.progress.pack(padx=10,pady=10)

f.pack()