Chapter 20. Progress Bar Widgets

Table of Contents
20.1. Progress Bar Example
20.2. Download Dialog Example

Inheritance Hierarchy

Object
   +--- Widget
         +--- Progress
               +--- ProgressBar
         

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 way 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.

$progress = new Gtk::ProgressBar();

$progress = new Gtk::ProgressBar( $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.

$progress->update( $percentage );

The argument is the amount "completed", meaning the amount the progress bar has been filled from 0-100%. This is passed to the function as a real number ranging from 0.0 to 1.0.

A progress bar may be set to one of a number of orientations using the function

$progress->set_orientation( $orientation );

The $orientation argument may take one of the following values to indicate the direction in which the progress bar moves:

'left_to_right'
'right_to_left'
'bottom_to_top'
'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 function.

$progress->set_bar_style( $style );

The $style parameter can take one of two values: 'continuous' or 'discrete'.

The number of discrete blocks can be set by calling:

$progress->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 function.

$progress->set_activity_mode( $activity_mode );

The step size of the activity indicator, and the number of blocks are set using the following functions.

$progress->set_activity_step( $step );

$progress->set_activity_blocks( $blocks );

When in continuous mode, the progress bar can also display a configurable text string within its trough, using the following function:

$progress->set_format_string( $format );

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

The displaying of this text string can be toggled using:

$progress->set_show_text( $show_text );

The $show_text argument is a true or false value. The appearance of the text can be modified further using:

$progress->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 functions. These functions return the formatted string that would be displayed within the trough.

$progress->get_current_text();

$progress->get_text_from_value( $value );

There is yet another way to change the range and value of a progress object using the following function:

$progress->configure( $value, $min, $max );

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

The remaining functions can be used to get and set the current value of a progess object in various types and formats:

        $progress->set_percentage( $percentage );

        $progress->set_value( $value );

        $progress->get_value();

        $progress->get_current_percentage();

        $progress->get_percentage_from_value( $adjustment );

These functions are pretty self explanatory. The last function 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 ) to give the illusion of multitasking. All will employ the update() function in the same manner.

20.1. Progress Bar Example

Here is an example of the progress bar, updated using timeouts. This code also shows you how to reset the Progress Bar.

Progress Bar Program Source

      
#!/usr/bin/perl -w

use Gtk;
use strict;

set_locale Gtk;
init Gtk;

my $false = 0;
my $true = 1;

my $window;
my $pbar;
my $timer;
my $align;
my $separator;
my $table;
my $adj;
my $button;
my $check1;
my $check2;
my $vbox;


# Create the window
$window = new Gtk::Window( "toplevel" );
$window->set_policy( $false, $false, $true );
$window->signal_connect( "destroy", sub { Gtk->exit( 0 ); } );
$window->set_title( "Progress Bar" );
$window->border_width( 0 );

$vbox = new Gtk::VBox( $false, 5 );
$vbox->border_width( 10 );
$window->add( $vbox );
$vbox->show();

# Create a centering alignment object
$align = new Gtk::Alignment( 0.5, 0.5, 0, 0 );
$vbox->pack_start( $align, $false, $false, 5 );
$align->show();

# Create a Adjusment object to hold the range of the progress bar
$adj = new Gtk::Adjustment( 0, 1, 150, 0, 0, 0 );

# Create the GtkProgressBar using the adjustment
$pbar = new_with_adjustment Gtk::ProgressBar( $adj );

# Set the format of the string that can be displayed in the
# trough of the progress bar:
#   %p - percentage
#   %v - value
#   %l - lower range value
#   %u - upper range value
$pbar->set_format_string( "%v from [%l-%u] (=%p%%)" );
$align->add( $pbar );
$pbar->show();

# Add a timer callback to update the value of the progress bar
$timer = Gtk->timeout_add( 100, \&progress_timeout );

$separator = new Gtk::HSeparator();
$vbox->pack_start( $separator, $false, $false, 0 );
$separator->show();

# rows, columns, homogeneous
$table = new Gtk::Table( 2, 3, $false );
$vbox->pack_start( $table, $false, $true, 0 );
$table->show();

# Add a check button to select displaying of the trough text
$check1 = new Gtk::CheckButton( "Show text" );
$table->attach( $check1, 0, 1, 0, 1, [ 'expand', 'fill' ],
		['expand', 'fill' ], 5, 5 );
$check1->signal_connect( "clicked", sub {
			    $pbar->set_show_text( $check1->active ); } );
$check1->show();

# Add a check button to toggle activity mode
$check2 = new Gtk::CheckButton( "Activity mode" );
$table->attach( $check2, 0, 1, 1, 2, [ 'expand', 'fill' ],
		[ 'expand', 'fill' ], 5, 5 );
$check2->signal_connect( "clicked", sub {
			    $pbar->set_activity_mode( $check2->active ); } );
$check2->show();

$separator = new Gtk::VSeparator();
$table->attach( $separator, 1, 2, 0, 2, [ 'expand', 'fill' ],
		[ 'expand', 'fill' ], 5, 5 );
$separator->show();

# Add a radio button to select continuous display mode
$button = new Gtk::RadioButton( "Continuous" );
$table->attach( $button, 2, 3, 0, 1, [ 'expand', 'fill' ],
		[ 'expand', 'fill' ], 5, 5 );
$button->signal_connect( "clicked", sub { 
			    $pbar->set_bar_style( 'continuous' ); } );
$button->show();

# Add a radio button to select discrete display mode
$button = new Gtk::RadioButton( "Discrete", $button );
$table->attach( $button, 2, 3, 1, 2, [ 'expand', 'fill' ],
		[ 'expand', 'fill' ], 5, 5 );
$button->signal_connect( "clicked", sub {
			    $pbar->set_bar_style( 'discrete' ); } );
$button->show();

$separator = new Gtk::HSeparator();
$vbox->pack_start( $separator, $false, $false, 0 );
$separator->show();

# Add a button to exit the program
$button = new Gtk::Button( "Close" );
$button->signal_connect( "clicked", sub { Gtk->exit( 0 ); } );

$vbox->pack_start( $button, $false, $false, 0 );

# This makes it so the button is the default.
$button->can_default( $true );

# This grabs this button to be the default button. Simply hitting
# the "Enter" key will cause this button to activate.
$button->grab_default();
$button->show();

$window->show();
main Gtk;
exit( 0 );



### Subroutines


# Timer callback to update the progress bar.

sub progress_timeout
{
   my ( $widget ) = @_;

   my $new_val;
   my $adj;

   # Calculate the value of the progress bar using the
   # value range set in the adjustment object

   $new_val = $pbar->get_value() + 1;
   $adj = $pbar->adjustment;
   $new_val = $adj->lower if ( $new_val > $adj->upper );

   # Set the new value
   $pbar->set_value( $new_val );

   # As this is a timeout function, return TRUE so that it
   # continues to get called
   return ( $true );
}


# END EXAMPLE PROGRAM
      
   

Progress Bar Example Screenshot

20.2. Download Dialog Example

Here is a slightly more advanced example showing how to use the output of one process as the value of the progress bar. It requires the wget program to work properly. Other ways of accomplishing the same thing is to use Unix IPC (do a man on perlipc) or threads (new in Perl 5.6.0). This would be a good example to tinker with.

Download Dialog using a Progress Bar Source

      
#!/usr/bin/perl -w

use Gtk;
use strict;

set_locale Gtk;
init Gtk;

my $true = 1;
my $false = 0;

my $command;
my $site;
my $dir;
my $file;
my $value;
my $signal;

my $window;
my $button;
my $vbox;
my $label;
my $adj;
my $pbar;


die "This program needs wget\n" if ( `which wget` =~ /^\s*$/ );

# Create the window.
$window = new Gtk::Window( 'toplevel' );
$signal = $window->signal_connect( 'delete_event', sub { Gtk->exit( 0 ); } );
$window->border_width( 15 );

$vbox = new Gtk::VBox( $false, 0 );
$window->add( $vbox );

# Label to let the user know what is going on.
$label = new Gtk::Label( "Downloading Gtk-Perl Tutorial" );
$vbox->pack_start( $label, $false, $false, 10 );
$label->show();

# Set up the progress bar
$adj = new Gtk::Adjustment( 0, 1, 100, 0, 0, 0 );
$pbar = new_with_adjustment Gtk::ProgressBar( $adj );
$vbox->pack_start( $pbar, $false, $false, 10 );
$pbar->set_format_string( "%p%%" );
$pbar->set_show_text( 1 );
$pbar->set_value( 0 );
$pbar->show();
$vbox->show();

# Runs the main loop as long as events are pending
Gtk->main_iteration while ( Gtk->events_pending );

$window->show();

# Set up wget
$command = "wget --dot-style=micro";
$site = "http://personal.riverusers.com";
$dir = "/~swilhelm/download/";
$file = "gtkperl-tutorial.tar.gz";

# Open a socket to intercept the outpt of wget.
open TMP, "$command $site$dir$file 2>&1 |";

while ( $value = <TMP> )
{
   $value =~ s/^.*\[//g;
   $value =~ s/ //g;
   $value =~ s/\%\]//g;
   chomp $value;

   $pbar->set_value( ++$value ) if ( $value =~ /^[0-9]+$/ );

   # Run the main loop as long as events are pending
   Gtk->main_iteration while ( Gtk->events_pending );
}

close TMP;

# Download is done, remove the progress bar and inform the user.
$vbox->remove( $pbar );

$label->set_text( "Download Complete" );

# Create the close button
$button = new Gtk::Button( "Close" );
$button->signal_connect( 'clicked', sub { Gtk->exit( 0 ); } );
$vbox->pack_start( $button, $false, $false, 0 );
$button->show();

main Gtk;
exit( 0 );


# END EXAMPLE PROGRAM
      
   

Download Dialog Screenshot