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 开发者_StackOverflow社区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:
- Is for C++, not Java
- 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)
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:
- You can't overrun your console width (80 character width is probably a safe assumption)
- Each iteration you must print as least as many visible characters as the previous iteration.
- 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 '%
'.
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");
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();
}
}
精彩评论