1 '''Michael Lange <klappnase (at) freakmail (dot) de>
   2 The Meter class provides a simple progress bar widget for Tkinter.
   3 
   4 INITIALIZATION OPTIONS:
   5 The widget accepts all options of a Tkinter.Frame plus the following:
   6 
   7     fillcolor -- the color that is used to indicate the progress of the
   8                  corresponding process; default is "orchid1".
   9     value -- a float value between 0.0 and 1.0 (corresponding to 0% - 100%)
  10              that represents the current status of the process; values higher
  11              than 1.0 (lower than 0.0) are automagically set to 1.0 (0.0); default is 0.0 .
  12     text -- the text that is displayed inside the widget; if set to None the widget
  13             displays its value as percentage; if you don't want any text, use text="";
  14             default is None.
  15     font -- the font to use for the widget's text; the default is system specific.
  16     textcolor -- the color to use for the widget's text; default is "black".
  17 
  18 WIDGET METHODS:
  19 All methods of a Tkinter.Frame can be used; additionally there are two widget specific methods:
  20 
  21     get() -- returns a tuple of the form (value, text)
  22     set(value, text) -- updates the widget's value and the displayed text;
  23                         if value is omitted it defaults to 0.0 , text defaults to None .
  24 '''
  25 
  26 import Tkinter
  27 
  28 class Meter(Tkinter.Frame):
  29     def __init__(self, master, width=300, height=20, bg='white', fillcolor='orchid1',\
  30                  value=0.0, text=None, font=None, textcolor='black', *args, **kw):
  31         Tkinter.Frame.__init__(self, master, bg=bg, width=width, height=height, *args, **kw)
  32         self._value = value
  33 
  34         self._canv = Tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\
  35                                     highlightthickness=0, relief='flat', bd=0)
  36         self._canv.pack(fill='both', expand=1)
  37         self._rect = self._canv.create_rectangle(0, 0, 0, self._canv.winfo_reqheight(), fill=fillcolor,\
  38                                                  width=0)
  39         self._text = self._canv.create_text(self._canv.winfo_reqwidth()/2, self._canv.winfo_reqheight()/2,\
  40                                             text='', fill=textcolor)
  41         if font:
  42             self._canv.itemconfigure(self._text, font=font)
  43 
  44         self.set(value, text)
  45         self.bind('<Configure>', self._update_coords)
  46 
  47     def _update_coords(self, event):
  48         '''Updates the position of the text and rectangle inside the canvas when the size of
  49         the widget gets changed.'''
  50         # looks like we have to call update_idletasks() twice to make sure
  51         # to get the results we expect
  52         self._canv.update_idletasks()
  53         self._canv.coords(self._text, self._canv.winfo_width()/2, self._canv.winfo_height()/2)
  54         self._canv.coords(self._rect, 0, 0, self._canv.winfo_width()*self._value, self._canv.winfo_height())
  55         self._canv.update_idletasks()
  56 
  57     def get(self):
  58         return self._value, self._canv.itemcget(self._text, 'text')
  59 
  60     def set(self, value=0.0, text=None):
  61         #make the value failsafe:
  62         if value < 0.0:
  63             value = 0.0
  64         elif value > 1.0:
  65             value = 1.0
  66         self._value = value
  67         if text == None:
  68             #if no text is specified use the default percentage string:
  69             text = str(int(round(100 * value))) + ' %'
  70         self._canv.coords(self._rect, 0, 0, self._canv.winfo_width()*value, self._canv.winfo_height())
  71         self._canv.itemconfigure(self._text, text=text)
  72         self._canv.update_idletasks()
  73 
  74 ##-------------demo code--------------------------------------------##
  75 
  76 def _demo(meter, value):
  77     meter.set(value)
  78     if value < 1.0:
  79         value = value + 0.005
  80         meter.after(50, lambda: _demo(meter, value))
  81     else:
  82         meter.set(value, 'Demo successfully finished')
  83 
  84 if __name__ == '__main__':
  85     root = Tkinter.Tk(className='meter demo')
  86     m = Meter(root, relief='ridge', bd=3)
  87     m.pack(fill='x')
  88     m.set(0.0, 'Starting demo...')
  89     m.after(1000, lambda: _demo(m, 0.0))
  90     root.mainloop()

Screenshot for the ProgressMeter Demo:

progressmeter.png

This Progress Meter is a good model for the general subject of how_to_keep_a_GUI_live_while_processing_continues_'in_the_background'.

tkinter: ProgressMeter (last edited 2010-08-19 17:37:13 by p54AA6BF4)