9.4. Progress Bars

Progress bars are used to show the status of an operation. They are pretty easy to use, as you will see with the code below. But first lets start out with the calls to create a new progress bar.

There are two ways to create a progress bar, one simple that takes no arguments, and one that takes an Adjustment object as an argument. If the former is used, the progress bar creates its own adjustment object.
 
progressbar = GtkProgressBar()

progressbar = GtkProgressBar(adjustment)

The second method has the advantage that we can use the adjustment object to specify our own range parameters for the progress bar.

The adjustment of a progress object can be changed dynamically using:
 
progress.set_adjustment(adjustment)

Now that the progress bar has been created we can use it.
 
progressbar.update(percentage)

The progressbar object is the progress bar you wish to operate on, and the argument is the amount "completed", meaning the amount the progress bar has been filled from 0-100%. This is passed to the method as a real number ranging from 0 to 1.

A progress bar may be set to one of a number of orientations using the method:
 
progressbar.set_orientation(orientation)

The orientation argument may take one of the following values to indicate the direction in which the progress bar moves:
 
  PROGRESS_LEFT_TO_RIGHT
  PROGRESS_RIGHT_TO_LEFT
  PROGRESS_BOTTOM_TO_TOP
  PROGRESS_TOP_TO_BOTTOM

When used as a measure of how far a process has progressed, the ProgressBar can be set to display its value in either a continuous or discrete mode. In continuous mode, the progress bar is updated for each value. In discrete mode, the progress bar is updated in a number of discrete blocks. The number of blocks is also configurable.

The style of a progress bar can be set using the following method.
 
progressbar.set_bar_style(style)

The style parameter can take one of two values:
 
  PROGRESS_CONTINUOUS
  PROGRESS_DISCRETE

The number of discrete blocks can be set by calling
 
progressbar.set_discrete_blocks(blocks)

As well as indicating the amount of progress that has occured, the progress bar may be set to just indicate that there is some activity. This can be useful in situations where progress cannot be measured against a value range. Activity mode is not effected by the bar style that is described above, and overrides it. This mode is either TRUE or FALSE, and is selected by the following method:
 
progressbar.set_activity_mode(activity_mode)

The step size of the activity indicator, and the number of blocks are set using the following methods:
 
progressbar.set_activity_step(step)

progressbar.set_activity_blocks(blocks)

When in continuous mode, the progress bar can also display a configurable text string within its trough, using the following method:
 
progressbar.set_format_string(format)

The format argument is similiar to one that would be used in a C printf statement. The following directives may be used within the format string:

The displaying of this text string can be toggled using:
 
progressbar.set_show_text(show_text)

The show_text argument is a boolean TRUE/FALSE value. The appearance of the text can be modified further using:
 
progressbar.set_text_alignment(x_align, y_align)

The x_align and y_align arguments take values between 0.0 and 1.0. Their values indicate the position of the text string within the trough. Values of 0.0 for both would place the string in the top left hand corner; values of 0.5 (the default) centres the text, and values of 1.0 places the text in the lower right hand corner.

The current text setting of a progress object can be retrieved using the current or a specified adjustment value using the following two methods. These methods return the formatted string that would be displayed within the trough.
 
progressbar.get_current_text()

progressbar.get_text_from_value(value)

There is yet another way to change the range and value of a progress object using the following method:
 
progressbar.configure(value, min, max)

This method provides quite a simple interface to the range and value of a progress object.

The remaining methods can be used to get and set the current value of a progess object in various types and formats:
 
progressbar.set_percentage(percentage)

progressbar.set_value(value)

progressbar.get_value()

progressbar.get_current_percentage()

progressbar.get_percentage_from_value(value)

These methods are pretty self explanatory. The last method uses the the adjustment of the specified progess object to compute the percentage value of the given range value.

Progress Bars are usually used with timeouts or other such functions (see section on Timeouts, I/O and Idle Functions) to give the illusion of multitasking. All will employ the update() method in the same manner.

The progressbar.py program provides an example of the progress bar, updated using timeouts. This code also shows you how to reset the Progress Bar. Figure 9.4 illustrates the resulting display:

Figure 9.4 ProgressBar Example

The source code for progressbar.py is:
 
    1   #!/usr/bin/env python
    2   
    3   # example progressbar.py
    4   
    5   import gtk
    6   
    7   # Update the value of the progress bar so that we get
    8   # some movement
    9   def progress_timeout(pbobj):
   10       # Calculate the value of the progress bar using the
   11       # value range set in the adjustment object
   12   
   13       new_val = pbobj.pbar.get_value() + 1
   14   
   15       if new_val > pbobj.adj.upper:
   16         new_val = pbobj.adj.lower
   17   
   18       # Set the new value
   19       pbobj.pbar.set_value(new_val)
   20   
   21       # As this is a timeout function, return TRUE so that it
   22       # continues to get called
   23       return gtk.TRUE
   24   
   25   class ProgressBar:
   26       # Callback that toggles the text display within the progress
   27       # bar trough
   28       def toggle_show_text(self, widget, data=None):
   29           self.pbar.set_show_text(widget.active)
   30   
   31       # Callback that toggles the activity mode of the progress
   32       # bar
   33       def toggle_activity_mode(self, widget, data=None):
   34           self.pbar.set_activity_mode(widget.active)
   35   
   36       # Callback that toggles the continuous mode of the progress
   37       # bar
   38       def set_continuous_mode(self, widget, data=None):
   39           self.pbar.set_bar_style(gtk.PROGRESS_CONTINUOUS)
   40   
   41       # Callback that toggles the discrete mode of the progress
   42       # bar
   43       def set_discrete_mode(self, widget, data=None):
   44           self.pbar.set_bar_style(gtk.PROGRESS_DISCRETE)
   45    
   46       # Clean up allocated memory and remove the timer
   47       def destroy_progress(self, widget, data=None):
   48           gtk.timeout_remove(self.timer)
   49           self.timer = 0
   50           gtk.mainquit()
   51   
   52       def __init__(self):
   53           self.window = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL)
   54           self.window.set_policy(gtk.FALSE, gtk.FALSE, gtk.TRUE)
   55   
   56           self.window.connect("destroy", self.destroy_progress)
   57           self.window.set_title("GtkProgressBar")
   58           self.window.set_border_width(0)
   59   
   60           vbox = gtk.GtkVBox(gtk.FALSE, 5)
   61           vbox.set_border_width(10)
   62           self.window.add(vbox)
   63           vbox.show()
   64     
   65           # Create a centering alignment object
   66           align = gtk.GtkAlignment(0.5, 0.5, 0, 0)
   67           vbox.pack_start(align, gtk.FALSE, gtk.FALSE, 5)
   68           align.show()
   69   
   70           # Create a Adjusment object to hold the range of the
   71           # progress bar
   72           self.adj = gtk.GtkAdjustment(0, 1, 150, 0, 0, 0)
   73   
   74           # Create the GtkProgressBar using the adjustment
   75           self.pbar = gtk.GtkProgressBar(self.adj)
   76   
   77           # Set the format of the string that can be displayed in the
   78           # trough of the progress bar:
   79           # %p - percentage
   80           # %v - value
   81           # %l - lower range value
   82           # %u - upper range value
   83           self.pbar.set_format_string("%v from [%l-%u] (=%p%%)")
   84           align.add(self.pbar)
   85           self.pbar.show()
   86   
   87           # Add a timer callback to update the value of the progress bar
   88           self.timer = gtk.timeout_add (100, progress_timeout, self)
   89   
   90           separator = gtk.GtkHSeparator()
   91           vbox.pack_start(separator, gtk.FALSE, gtk.FALSE, 0)
   92           separator.show()
   93   
   94           # rows, columns, homogeneous
   95           table = gtk.GtkTable(2, 3, gtk.FALSE)
   96           vbox.pack_start(table, gtk.FALSE, gtk.TRUE, 0)
   97           table.show()
   98   
   99           # Add a check button to select displaying of the trough text
  100           check = gtk.GtkCheckButton("Show text")
  101           table.attach(check, 0, 1, 0, 1,
  102                        gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
  103                        5, 5)
  104           check.connect("clicked", self.toggle_show_text)
  105           check.show()
  106   
  107           # Add a check button to toggle activity mode
  108           check = gtk.GtkCheckButton("Activity mode")
  109           table.attach(check, 0, 1, 1, 2,
  110                        gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
  111                        5, 5)
  112           check.connect("clicked", self.toggle_activity_mode)
  113           check.show()
  114   
  115           separator = gtk.GtkVSeparator ()
  116           table.attach(separator, 1, 2, 0, 2,
  117                        gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
  118                        5, 5)
  119           separator.show()
  120   
  121           # Add a radio button to select continuous display mode
  122           button = gtk.GtkRadioButton(None, "Continuous")
  123           table.attach(button, 2, 3, 0, 1,
  124                        gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
  125                        5, 5)
  126           button.connect("clicked", self.set_continuous_mode)
  127           button.show()
  128   
  129           # Add a radio button to select discrete display mode
  130           button = gtk.GtkRadioButton(button, "Discrete")
  131           table.attach(button, 2, 3, 1, 2,
  132                        gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL,
  133                        5, 5)
  134           button.connect("clicked", self.set_discrete_mode)
  135           button.show ()
  136   
  137           separator = gtk.GtkHSeparator()
  138           vbox.pack_start(separator, gtk.FALSE, gtk.FALSE, 0)
  139           separator.show()
  140   
  141           # Add a button to exit the program
  142           button = gtk.GtkButton("close")
  143           button.connect_object("clicked", self.window.destroy, self.window)
  144           vbox.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
  145   
  146           # This makes it so the button is the default.
  147           button.set_flags(gtk.CAN_DEFAULT)
  148   
  149           # This grabs this button to be the default button. Simply hitting
  150           # the "Enter" key will cause this button to activate.
  151           button.grab_default ()
  152           button.show()
  153   
  154           self.window.show()
  155   
  156   def main():
  157       gtk.mainloop()
  158       return 0
  159   
  160   if __name__ == "__main__":
  161       ProgressBar()
  162       main()