http://www.perlmonks.org?node_id=139305
Category: Fun Stuff
Author/Contact Info Sean Cross (symuc@familycross.com)
Description: Reminiscent of the status bar that showed the progress of the startup of the classic game "Doom", this code will print a status bar of variable width with an optional header and/or footer.
 ####################################
## FUNCTION: StatusBar ###############
##################################################
##                                              ##
##   Generates a statusbar that is of variable  ##
## width, and is very adaptable, optionally     ##
## displaying the percentage as well.           ##
##                                              ##
## ARGS:                                        ##
##      0) The text preceeding the bar          ##
##      1) The current value                    ##
##      2) The maximum value                    ##
##      3) The size of the bar (in characters)  ##
##      4) Display the percentage?              ##
##      5) The text following the bar           ##
## Returns:                                     ##
##      NULL                                    ##
##                                              ##
##################################################

sub StatusBar {
  my $level;
  my $numdots;
  my $numblanks;

  my $pre=$_[0];
  my $cur=int($_[1]);
  my $max=int($_[2]);
  my $size=int($_[3]);
  my $disp=$_[4];
  my $i;
  my $post=$_[5];

  $level = $cur/$max;
  
  $numdots = int($level * $size);

  $numblanks = $size - $numdots;

  print $pre . "\t";
  print " [";
  for($i = 0; $i < $numdots; $i++) {
    print ".";
  }
  for($i = 0; $i < $numblanks; $i++) {
    print " ";
  }
  print "]";
  if($disp ne "") {
    printf(" ($cur/$max, %3.2f%%)", (int($level*10000)/100));
  }
  print " $post\r";
}

Edited 2002-01-16 to fix html entities dvergin

Replies are listed 'Best First'.
Re: Doom-Style Status Bar
by particle (Vicar) on Jan 17, 2002 at 05:15 UTC
    i tested your code, as formatted by simon.proctor, and decided to modify it to accept a hash as input. i added some minor error checking, and modified your print statements a bit.

    here's the code in a full script with a few test runs. below is output, and an explanation of what i did.

    #!/usr/local/bin/perl -w use strict; $|=1; sub StatusBar { my %args = @_; # test for must-have values (cur, max, size) unless( defined($args{cur}) ) { die("cur not defined"); } unless( defined($args{max}) ) { die("max not defined"); } if( defined($args{size}) ) { $args{size} = int( $args{size} ) } else { die("size not defined"); } # make sure cur <= max unless( $args{cur} <= $args{max} ) { die("cur greater than max"); +} # compute percentage level ( cur / max ) my $level = $args{cur} / $args{max}; # compute number of dots to display ( level * size ), return integ +er part # WARNING!!! int() truncates a number, does not round my $numdots = int( $level * $args{size} ); # print status bar defined($args{pre}) && print "$args{pre}\t"; print "[", "." x $numdots, " " x ( $args{size} - $numdots ), "]"; if($args{disp}) { $args{disp} && printf(" (%3.2f%%)", ($level*100)); } defined($args{post}) && print " $args{post}\n"; } # create hash of standard arguments my %standard_args = ( pre => "begin", max => 100, size => 10, disp => 1, post => "end", ); # test 1, standard call StatusBar( pre => "begin", cur => 79, max => 100, size => 10, disp => 1, post => "end", ); # test 2, use %standard_args, override max, add cur StatusBar( %standard_args, cur => 72.5, max => 91, ); # test 3, standard call with different values StatusBar( pre => "begin", cur => 41, max => 90, size => 15, disp => 0, post => "end", ); # test 4, standard call StatusBar( pre => "begin", cur => 7, max => 90, size => 14, disp => 1, post => "end", ); # # uncomment these to test errors # test 5, cur > max # StatusBar( # cur => 20, # max => 10, # size => 11, # ); # # test 6, cur not passed # StatusBar( # max => 100, # size => 10, # disp => 1, # );
    here's the output:

    begin [....... ] (79.00%) end begin [....... ] (79.67%) end begin [...... ] (45.56%) end begin [. ] (7.78%) end

    i used a hash for input for a few reasons:
    1> it's more readable, therefore, more supportable. hash key/value pairs make the information passed to the subroutine call easier to understand.
    2> it's more flexible. you can create a hash of standard arguments, and add to or overwrite the standard values as they're passed to the subroutine.
    3> it's more perlish.

    i added a bit of error checking, to give you a general idea, but you might want to do more. bounds checking, verifying your input are valid numbers, etc.

    i modified the print statement a bit, by using a little perlish trick, print "." x $numdots;.

    your idea was a good one, and keep working on your code. i'll probably find use for this in a few of my applications; my users are always looking for more status information.

    ~Particle

Re: Doom-Style Status Bar
by simon.proctor (Vicar) on Jan 17, 2002 at 03:32 UTC
    I haven't tested it but your code needed reworking so that the downloaded version would compile.

    Update: I wrapped it in a test script for you :). I also added flushing and a sleep to simulate something running slowly (which we were tracking).
    #! d:/perl/bin/perl -w use strict; $|++; my $min = 1; my $max = 100; while($min != $max) { sleep(1); StatusBar('before',$min,$max,25,'y','after'); $min++; } sub StatusBar { my $level; my $numdots; my $numblanks; my $pre=$_[0]; my $cur=int($_[1]); my $max=int($_[2]); my $size=int($_[3]); my $disp="$_[4]"; my $i; my $post=$_[5]; $level = $cur/$max; $numdots = int($level * $size); $numblanks = $size - $numdots; print $pre . "\t"; print " ["; for($i = 0; $i < $numdots; $i++) { print "."; } for($i = 0; $i < $numblanks; $i++) { print " "; } print "]"; if($disp ne "") { printf(" ($cur/$max, %3.2f%%)", (int($level*10000)/100)); } print " $post\r"; }

    Simon

    You're only jealous cos the voices are talking to me