4

I was just wondering if there was a way to use System.out.println(); or other methods to create a cool loading bar when I run my program with a batch file.

The real question here is how I can make this bar appear as if it's printing on only one line.

I don't want it to be spread over multiple lines like below:

[aaaaaccccccccccccccc] 25%
[aaaaaaaaaacccccccccc] 50%
[aaaaaaaaaaaaaaaccccc] 75%

One that stays cleanly in place would make things cleaner and friendlier.

Many thanks,

Justian

EDIT:

Ok. I managed to find this link here: How to animate the command line?, but the answer:

  1. Is for C++, not Java
  2. Doesn't seem very efficient in Java, having to backspace each line in a loop?

Is there a better way to do this in Java?

EDIT:

Here's what I ended up going with:

static final int PROGRESSBAR_LENGTH = 20;

public static void drawProgressBar(int numerator, int denominator) {
    int percent = (int) (((double) numerator / (double) denominator) * 100);

    String bar = "[";
    int lines = round((PROGRESSBAR_LENGTH * numerator) / denominator);
    int blanks = PROGRESSBAR_LENGTH - lines;

    for (int i = 0; i < lines; i++)
        bar += "|";

    for (int i = 0; i < blanks; i++)
        bar += " ";

    bar += "] " + percent + "%";

    System.out.print(bar + "\r");
}

private static int round(double dbl) {
    int noDecimal = (int) dbl;
    double decimal = dbl - noDecimal;

    if (decimal >= 0.5)
        return noDecimal + 1;
    else
        return noDecimal;
}

Sample output:

[||||||||||||||||....] 80% (. = space)

Justian Meyer
  • 3,623
  • 9
  • 35
  • 53
  • possible duplicate of http://stackoverflow.com/questions/439799/ – krock Jul 12 '10 at 03:36
  • I see why you might think this is a duplicate, but my question is definitely more specific. I could probably accomplish this task without the use of additional classes. – Justian Meyer Jul 12 '10 at 03:42
  • This method might work: http://stackoverflow.com/questions/852665/command-line-progress-bar-in-java . It took me a second to consider searching "progress bar" and not "loading bar". >> – Justian Meyer Jul 12 '10 at 03:45
  • I ended up making a more advanced loading bar in the end that would support more than one process (loop). It segmented the processes into parts (organized in a 2D Array) and worked down the parts until all were completed. – Justian Meyer Jul 12 '10 at 15:57
  • Possible duplicate of [Command line progress bar in Java](https://stackoverflow.com/questions/852665/command-line-progress-bar-in-java) – BuZZ-dEE Jul 16 '18 at 22:25

3 Answers3

5

As an alternative to printing the backspace character, you can use the carriage return character: 13 (decimal), 0xD (hexadecimal), or \r (escaped character).

There are three stipulations:

  1. You can't overrun your console width (80 character width is probably a safe assumption)
  2. Each iteration you must print as least as many visible characters as the previous iteration.
  3. When you want to move on (when you're done with your loading bar or whatever), you need to lead with a newline, or else you'll start overwriting your existing loading bar with new text.

So, something along these lines:

public static void loadMyProgram() {
    while(programStillLoading) {
        doSomeLoading();
        double loadFraction = howCloseToDone(); // A number between 0 and 1

        System.out.print("[");
        int i = 0;
        for( ; i < (int)(loadFraction * 20); i++)
            System.out.print("=");
        for( ; i < 20; i++)
            System.out.print(" ");
        System.out.print("] " + (int)(loadFraction * 100) + "%");

        System.out.print((char)13);
        //System.out.print((char)0xD); // Same as above, but in hex
        //System.out.print("\r"); // Same as above, but as the symbol
    }

    System.out.println();
}

The above will print [<bar>] <percent>%, where <bar> is 0..p '=' followed by 0..(20-p) ''. It will stay on a single line.

Assuming your calculation of the load percentage is monotonically increasing (in other words, it doesn't act like a Windows loading bar, going from 20% to 110% to 1% in the span of 3 seconds), you don't have to worry about ensuring your next output is equal to or longer than your previous output, because that will always be true. However, in this case you could take care of it with two spaces after the '%'.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
Brian S
  • 4,878
  • 4
  • 27
  • 46
  • I ended up using this method. So nice and clean :). I'll post my code above. Thanks! – Justian Meyer Jul 12 '10 at 04:18
  • 1
    I referenced this code and was misled by the variable name, which led to me unnecessarily multiplying by 100. The name implied that the value should be a percentage - that is, a number between 0 and 100 - when it should be a number between 0 and 1. I edited in hopes of saving others from making the same mistake. Are you offended? – Matt Ball May 09 '14 at 22:27
  • @MattBall, Not offended, just confused. When I see "percentage" in calculations, I think [0..1], not [0..100]. :) – Brian S May 09 '14 at 22:37
  • 1
    ["In mathematics, a percentage is a number or ratio expressed as a fraction of 100... The word 'percent' means 'out of 100' or 'per 100'."](http://en.wikipedia.org/wiki/Percentage) – Matt Ball May 09 '14 at 22:56
0

I've done this using the backspace approach - it seems to work fine.

Just use System.out.print() instead of System.out.println() -- so you don't get carriage returns.

You'll need to keep track of how many backspaces you need to print, but it works fine.

BTW - to print a backspace in java, use:

System.out.print("\b");
desau
  • 3,001
  • 1
  • 24
  • 27
  • It seems like such a memory hog, though. If the process takes time as it is, why slow it down further with a loading bar? – Justian Meyer Jul 12 '10 at 03:53
  • I don't understand what you mean by memory hog. How is this using any additional memory? Perhaps a byte or two for storing the number of backspaces .. but really .. 2 bytes? If you're worried about that sort of memory constraints, you should probably be using assembly, not Java. Also - yes - more CPU cycles .. but again, pretty minimal. If you're worried about a couple extra CPU cycles, you probably don't want to print progress at all. – desau Jul 12 '10 at 04:21
  • Yeah, I meant cycles. Apologies. It's not so much that it'll cause much lag, so much as there's obviously a better way than that extra loop. The "\r" method works much better. Thanks for the help, regardless. :) – Justian Meyer Jul 12 '10 at 04:27
-1

This might be a place to start.

Usage:

ProgressBar pb = new ProgressBar(10,1);
while (loadingStuff) {
  doStuff();
  pb.update();
}
pb.finish();

The class:

public class ProgressBar {
    
      private static String[] s;
      private int pos, increment, size;
    
      public ProgressBar(int size, int increment) {
        this.size = size;
        this.increment = increment;
        s = new String[size+2];  
        Arrays.fill(s,"a");
        s[0] = "[";
        s[size+1] = "]";
      }
    
      public void update() {
          System.out.println('\r');
          if (pos+inc<size+2) {
              Arrays.fill(s,pos,pos+inc,"c");
              pos += inc;
          }
          for (String ch : s) {
              System.out.print(ch);
          }  
      }
    
      public void finish() {
          System.out.println();
      }
}
xagyg
  • 9,562
  • 2
  • 32
  • 29