Command line progress bar in Java

Viewed 113003

I have a Java program running in command line mode. I would like to display a progress bar, showing the percentage of job done. The same kind of progress bar you would see using wget under unix. Is this possible?

18 Answers

I have implemented this sort of thing before. Its not so much about java, but what characters to send to the console.

The key is the difference between \n and \r. \n goes to the start of a new line. But \r is just carriage return - it goes back to the start of the same line.

So the thing to do is to print your progress bar, for example, by printing the string

"|========        |\r"

On the next tick of the progress bar, overwrite the same line with a longer bar. (because we are using \r, we stay on the same line) For example:

"|=========       |\r"

What you have to remember to do, is when done, if you then just print

"done!\n"

You may still have some garbage from the progress bar on the line. So after you are done with the progress bar, be sure to print enough whitespace to remove it from the line. Such as:

"done             |\n"

Hope that helps.

C# Example but I'm assuming this is the same for System.out.print in Java. Feel free to correct me if I'm wrong.

Basically, you want to write out the \r escape character to the start of your message which will cause the cursor to return to the start of the line (Line Feed) without moving to the next line.

    static string DisplayBar(int i)
    {
        StringBuilder sb = new StringBuilder();

        int x = i / 2;
        sb.Append("|");
        for (int k = 0; k < 50; k++)
            sb.AppendFormat("{0}", ((x <= k) ? " " : "="));
        sb.Append("|");

        return sb.ToString();
    }

    static void Main(string[] args)
    {
        for (int i = 0; i <= 100; i++)
        {
            System.Threading.Thread.Sleep(200);
            Console.Write("\r{0} {1}% Done", DisplayBar(i), i);
        }

        Console.ReadLine();

    }

A bit refactored and updated @maytham-ɯɐɥʇʎɐɯ 's method. Now it's supporting an arbitrary size of the progress bar:

    public static void progressPercentage(int done, int total) {
        int size = 5;
        String iconLeftBoundary = "[";
        String iconDone = "=";
        String iconRemain = ".";
        String iconRightBoundary = "]";

        if (done > total) {
            throw new IllegalArgumentException();
        }
        int donePercents = (100 * done) / total;
        int doneLength = size * donePercents / 100;

        StringBuilder bar = new StringBuilder(iconLeftBoundary);
        for (int i = 0; i < size; i++) {
            if (i < doneLength) {
                bar.append(iconDone);
            } else {
                bar.append(iconRemain);
            }
        }
        bar.append(iconRightBoundary);

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

        if (done == total) {
            System.out.print("\n");
        }
    }

I edited Eoin Campbell's code to java and added formatted progress in percents.

public static String progressBar(int currentValue, int maxValue) {
    int progressBarLength = 33; //
    if (progressBarLength < 9 || progressBarLength % 2 == 0) {
        throw new ArithmeticException("formattedPercent.length() = 9! + even number of chars (one for each side)");
    }
    int currentProgressBarIndex = (int) Math.ceil(((double) progressBarLength / maxValue) * currentValue);
    String formattedPercent = String.format(" %5.1f %% ", (100 * currentProgressBarIndex) / (double) progressBarLength);
    int percentStartIndex = ((progressBarLength - formattedPercent.length()) / 2);

    StringBuilder sb = new StringBuilder();
    sb.append("[");
    for (int progressBarIndex = 0; progressBarIndex < progressBarLength; progressBarIndex++) {
        if (progressBarIndex <= percentStartIndex - 1
        ||  progressBarIndex >= percentStartIndex + formattedPercent.length()) {
            sb.append(currentProgressBarIndex <= progressBarIndex ? " " : "=");
        } else if (progressBarIndex == percentStartIndex) {
            sb.append(formattedPercent);
        }
    }
    sb.append("]");
    return sb.toString();
}

int max = 22;
System.out.println("Generating report...");
for (int i = 0; i <= max; i++) {
   Thread.sleep(100);
   System.out.print(String.format("\r%s", progressBar(i, max)));
}
System.out.println("\nSuccessfully saved 32128 bytes");

And output:

Generating report...

[========      24.2 %             ]

[============  45.5 %             ]

[============  78.8 % =====       ]

[============  87.9 % ========    ]

[============ 100.0 % ============]

Successfully saved 32128 bytes

This would be possible with a Java Curses library. This is what I have found. I haven't used it myself and I don't know if it is cross-platform.

static String progressBar(int progressBarSize, long currentPosition, long startPositoin, long finishPosition) {
    String bar = "";
    int nPositions = progressBarSize;
    char pb = '░';
    char stat = '█';
    for (int p = 0; p < nPositions; p++) {
        bar += pb;
    }
    int ststus = (int) (100 * (currentPosition - startPositoin) / (finishPosition - startPositoin));
    int move = (nPositions * ststus) / 100;
    return "[" + bar.substring(0, move).replace(pb, stat) + ststus + "%" + bar.substring(move, bar.length()) + "]";
}

image

It doesn't need to be complicated.

enter image description here

public class Demo {
  private static final StringBuilder sb = new StringBuilder();

  public static void main (String[] args) throws java.lang.Exception
  {
    for (int i = 0 ; i <= 100 ; i++) {
      sb.setLength(0);
      for (int j = 0 ; j < i; j++) {
        sb.append("#");
      }
      Thread.sleep(100);
      System.out.print("[" + String.format("%-100s", sb.toString()) + "] " +  i + "%");
      System.out.print("\r");
    }
  }
}

public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println("Loading : ");
            int count =1;
            for(int j=1;j<150;j++){

                System.out.print("\r");
                if(count==1){
                    System.out.print("/");
                    count++;
                }
                else if(count==2){
                    System.out.print("|");
                    count++;
                }
                else if(count==3){
                    System.out.print("-");
                    count++;
                }
                else if(count==4){
                    System.out.print("\\");
                    count++;
                }
                else if(count==5){
                    System.out.print("|");
                    count++;
                }
                else
                    count = 1;
            Thread.sleep(200);
        }

        }

    }
public class ConsoleApp {
    static String DisplayBar(int i)
    {
        StringBuilder sb = new StringBuilder();

        int x = i / 2;
        sb.append("|");
        for (int k = 0; k < 50; k++)
            sb.append(String.format("%s", ((x <= k) ? " " : "=")));
        sb.append("|");

        return sb.toString();
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i <= 100; i++)
        {
            Thread.sleep(200);
            System.out.printf("\r%s %s  Done", DisplayBar(i), i);
        }
    }
}

I have created a ProgressBar that has everything you might need in it.

I even documented it!

And I also compiled it for faster usage.

I know that nobody has to do this, but Im still seeing people having the same problem 10 years later!

Here's an example:

//...
  //For demo only!
  public static void main(String[]a){
    final ProgressBar progress=new ProgressBar(100);
    progress.printBar();
    for(int i=0;i<100;i++){
      progress.addValue();
      progress.printBar();
      try{
        java.lang.Thread.sleep(100);
      }catch(Exception e){}
    }
  }
//...

This is not for promotion, made this to help people not waste their time in coding classes themselves!

Related