2

I am trying to make a progress bar like this

[#        ] 10%
[#####    ] 50%
[#########] 100%

What i tried

public static void main(String[] args) throws InterruptedException {
        String format = "[#          ]%d%%\r";
        for(int i=0;i<=100;i++){
            System.out.print(String.format(format, i));
            Thread.sleep(10);
        }
}

output:

[#        ] 10%
[#        ] 50%
[#        ] 100%

the problem is I can't increment the the # count according to the progress.

So how can i move or increment the # ?

theapache64
  • 10,926
  • 9
  • 65
  • 108

4 Answers4

2

You need to write a piece of code that produces a ten-character String starting in #s and ending in spaces. Pass this method a number from 0 to 100. The method should divide the number by ten, rounding the result up. This will give you the number of # characters in the ten-character bar:

int numPounds = (pct + 9) / 10;

Make a loop that appends '#' numPounds times, and then appends ' ' until the length of the string is ten. Print the result between [ ... ] characters to complete the exercise.

private static final StringBuilder res = new StringBuilder();;

static String progress(int pct) {
    res.delete(0, res.length());
    int numPounds = (pct + 9) / 10;
    for (int i = 0 ; i != numPounds ; i++) {
        res.append('#');
    }
    while (res.length() != 10) {
        res.append(' ');
    }
    return res.toString();
}

public static void main (String[] args) throws java.lang.Exception
{
    for (int i = 0 ; i <= 100 ; i++) {
        Thread.sleep(10);
        System.out.print(String.format("[%s]%d%%\r", progress(i), i));
    }
}
theapache64
  • 10,926
  • 9
  • 65
  • 108
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

take a look at this

static int current=0;
static int previous=0;
static String previousString="";
public static void main(String[] args) throws InterruptedException {
    String format = "[%s]%d%%\r";

    for (int i = 0; i <= 100; i++) {
        try {
            current=i/10;
            System.out.print(String.format(format, repeat("#",current ), i));
        } catch (ArithmeticException e) {
            System.out.print(String.format(format, repeat("#", 0), i));
        }
        Thread.sleep(10);
    }
}

static String repeat(String StringToRepat, int repetition) {
    if (repetition==previous)
    {
        return previousString;
    }
    StringBuilder builder = new StringBuilder("");
    for (int i = 0; i < repetition; i++)
        builder.append(StringToRepat);
    previousString=builder.toString();
    previous=repetition;
    return previousString;


}
QuakeCore
  • 1,886
  • 2
  • 15
  • 33
  • I am not sure whether this meets your expectations or not, but feel free to ask for any modification/explanations. – QuakeCore Aug 02 '15 at 11:19
  • 1
    i think the `repeat` method will create 100 instance of `StringBuilder`. isn't ? – theapache64 Aug 02 '15 at 11:30
  • 1
    yes, but once the repeat method block ends the StringBuilder object will be garbage-collected, so it should cause you no problem, and its much more merciful than using String. – QuakeCore Aug 02 '15 at 11:33
  • but that's expensive dude. i want something simple. – theapache64 Aug 02 '15 at 11:35
  • @ShifarShifz `simple` != `with best performance`. What you see here is *simple* solution, but as you correctly noted it may be unnecessary expensive. You can optimize by using one `StringBuilder` and do the test if we should append new `#` character to in in main loop. – Pshemo Aug 02 '15 at 11:39
  • What if we initialize the `StringBuilder` outside the methods - within the class and `clear()` the `StringBuilder` @ `repeat()` where the `StringBuilder` initialized in the above answer. ? – theapache64 Aug 02 '15 at 11:44
  • 1
    @ShifarShifz Then your solution will not be thread-safe because in the middle of one task can appear new thread and reset it. And sine task-bars are usually called in one thread to show progress of other thread that solution is not recommended. – Pshemo Aug 02 '15 at 11:46
  • 1
    @ShifarShifz now only 10 sb instances are created, but as you can see the code before editing made more sense, and since this answer cannot be generalize to another problems I will keep it this way, but note that this is merely an optimization,this solution is so far away from being thread-safe and creating 100 sb is generally harmless. – QuakeCore Aug 02 '15 at 11:46
1

All credits goes to @Poshemo

public static void main(String[] args) throws InterruptedException {
    final StringBuilder sb  =  new StringBuilder();
    String format = "[%-11s]%d%%\r";

    for(int i=0;i<=100;i++){
        if(i%10==0){
            sb.append("#");
        }
        System.out.print(String.format(format, sb, i));
        Thread.sleep(10);
    }
}
Pshemo
  • 122,468
  • 25
  • 185
  • 269
theapache64
  • 10,926
  • 9
  • 65
  • 108
  • 2
    One advice: never concatenate result string with new part inside loop like `hash+="#"` because each time you need to create new string which needs to copy old string and new part. Instead use `StringBuilder` which will already have copy of old string and simply `append` new part. After you are done just call `toStirng` on StringBuilder if you need String. – Pshemo Aug 02 '15 at 11:34
  • fine. :) . am in new in programming. very thanks for the information. – theapache64 Aug 02 '15 at 11:37
  • @Pshemo : i just modified the answer. please look into it and tell me any modification needed. – theapache64 Aug 02 '15 at 11:40
  • 1
    `%s` can handle ensuring that it will take 10 characters. For instance `[%10s]` and and string `"foo"` will generate `[ foo]` and `[%-10s]` will generate `[foo ]`. – Pshemo Aug 02 '15 at 11:43
  • Forgot that we can't print more than one continuous spaces in comments. Just assume that there are more of them before or after `foo`. – Pshemo Aug 02 '15 at 11:44
  • Wowww, that's awesome. – theapache64 Aug 02 '15 at 11:50
  • 1
    You should be able to remove `format = format.replaceFirst(" ", "");` now since you are using `%[-limit]s` to ensure correct number of spaces. – Pshemo Aug 02 '15 at 11:50
  • Why don't you answer the question then ?. – theapache64 Aug 02 '15 at 11:52
  • Because I am here to help solving problems with existing code, not to write one, and your original code didn't have part which would even attempt to generate correct number of `#` which needs to be fixed. Many SO users does so. We try not to encourage people to post code writing requests, but to try first and come back if they will fail. – Pshemo Aug 02 '15 at 11:54
  • You can accept your own answer later. Also +1 for reserving `12` characters instead of `10`, that is simplest and best solution which you could use IMO. – Pshemo Aug 02 '15 at 12:01
  • Am not here to earn points, i just want to learn. and there are people who made answers before. so they deserve the green tick. ;) – theapache64 Aug 02 '15 at 12:08
  • There is one problem with 12 character solution. Because you initialized StringBuilder with `#` and are appending one `#` when `i` is multiplication of 10 your current solution will have `##` for `0%` instead of `#` or even none of them. Simple solution would be initializing builder without first `#` character and reserving `11` characters. – Pshemo Aug 02 '15 at 12:12
  • About your last comment, purpose of green tick is not to give points, but to mark best answer, points are something extra and you will not get any for marking your own answer so you will not *cheat the system*. If you think that some answers ware useful for you and want to show appreciation simple upvote should be enough. – Pshemo Aug 02 '15 at 12:15
  • Oh, we don't get points to our answer upon our own question ? – theapache64 Aug 02 '15 at 13:17
  • We don't get points for accepting our own answer. It prevents others from posting very simple self-answered questions just to get points for accepting our own answer. But we get points if someone else *up-votes* answer. – Pshemo Aug 02 '15 at 13:22
0

I needed a progress bar for a project, I just put it on Github in case it can help somebody.

Basic idea is that your main task is divided into subtasks, you just notify the bar the advances of the subtask and the display is done automatically.

Sample usage with randomized timings:

ConsoleProgressBar bar = new ConsoleProgressBar(numberOfSubtasks);
bar.startAndDisplay();
for (int i = 0; i < numberOfSubtasks; i += increment) {
 bar.updateAndDisplay(increment);
 Thread.sleep(minrandomTime + rand.nextInt(maxrandomTime - minrandomTime));
}
Julien
  • 1,302
  • 10
  • 23