How to display a progress indicator in pure C/C++ (cout/printf)?

后端 未结 8 1366
夕颜
夕颜 2020-12-12 11:10

I\'m writing a console program in C++ to download a large file. I have known the file size, and I start a work thread to download. I want to show a progress indicator to mak

相关标签:
8条回答
  • 2020-12-12 11:17

    Take a look at boost progress_display

    http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display

    I think it may do what you need and I believe it is a header only library so nothing to link

    0 讨论(0)
  • 2020-12-12 11:19

    I know I am a bit late in answering this question, but I made a simple class that does exactly what you want. (keep in mind that I wrote using namespace std; before this.):

    class pBar {
    public:
        void update(double newProgress) {
            currentProgress += newProgress;
            amountOfFiller = (int)((currentProgress / neededProgress)*(double)pBarLength);
        }
        void print() {
            currUpdateVal %= pBarUpdater.length();
            cout << "\r" //Bring cursor to start of line
                << firstPartOfpBar; //Print out first part of pBar
            for (int a = 0; a < amountOfFiller; a++) { //Print out current progress
                cout << pBarFiller;
            }
            cout << pBarUpdater[currUpdateVal];
            for (int b = 0; b < pBarLength - amountOfFiller; b++) { //Print out spaces
                cout << " ";
            }
            cout << lastPartOfpBar //Print out last part of progress bar
                << " (" << (int)(100*(currentProgress/neededProgress)) << "%)" //This just prints out the percent
                << flush;
            currUpdateVal += 1;
        }
        std::string firstPartOfpBar = "[", //Change these at will (that is why I made them public)
            lastPartOfpBar = "]",
            pBarFiller = "|",
            pBarUpdater = "/-\\|";
    private:
        int amountOfFiller,
            pBarLength = 50, //I would recommend NOT changing this
            currUpdateVal = 0; //Do not change
        double currentProgress = 0, //Do not change
            neededProgress = 100; //I would recommend NOT changing this
    };
    

    An example on how to use:

    int main() {
        //Setup:
        pBar bar;
        //Main loop:
        for (int i = 0; i < 100; i++) { //This can be any loop, but I just made this as an example
            //Update pBar:
            bar.update(1); //How much new progress was added (only needed when new progress was added)
            //Print pBar:
            bar.print(); //This should be called more frequently than it is in this demo (you'll have to see what looks best for your program)
            sleep(1);
        }
        cout << endl;
        return 0;
    }
    

    Note: I made all of the classes' strings public so the bar's appearance can be easily changed.

    0 讨论(0)
  • 2020-12-12 11:20

    For a C solution with an adjustable progress bar width, you can use the following:

    #define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
    #define PBWIDTH 60
    
    void printProgress(double percentage) {
        int val = (int) (percentage * 100);
        int lpad = (int) (percentage * PBWIDTH);
        int rpad = PBWIDTH - lpad;
        printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, "");
        fflush(stdout);
    }
    

    It will output something like this:

     75% [||||||||||||||||||||||||||||||||||||||||||               ]
    
    0 讨论(0)
  • 2020-12-12 11:21

    With a fixed width of your output, use something like the following:

    float progress = 0.0;
    while (progress < 1.0) {
        int barWidth = 70;
    
        std::cout << "[";
        int pos = barWidth * progress;
        for (int i = 0; i < barWidth; ++i) {
            if (i < pos) std::cout << "=";
            else if (i == pos) std::cout << ">";
            else std::cout << " ";
        }
        std::cout << "] " << int(progress * 100.0) << " %\r";
        std::cout.flush();
    
        progress += 0.16; // for demonstration only
    }
    std::cout << std::endl;
    

    http://ideone.com/Yg8NKj

    [>                                                                     ] 0 %
    [===========>                                                          ] 15 %
    [======================>                                               ] 31 %
    [=================================>                                    ] 47 %
    [============================================>                         ] 63 %
    [========================================================>             ] 80 %
    [===================================================================>  ] 96 %
    

    Note that this output is shown one line below each other, but in a terminal emulator (I think also in Windows command line) it will be printed on the same line.

    At the very end, don't forget to print a newline before printing more stuff.

    If you want to remove the bar at the end, you have to overwrite it with spaces, to print something shorter like for example "Done.".

    Also, the same can of course be done using printf in C; adapting the code above should be straight-forward.

    0 讨论(0)
  • 2020-12-12 11:24

    Here is a simple one I made:

    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    int barl = 20;
    
    int main() {
       system("color 0e");  
       cout << "[";     
       for (int i = 0; i < barl; i++) {         
          Sleep(100);       
          cout << ":";  
       }
       cout << "]";
    }
    
    0 讨论(0)
  • 2020-12-12 11:28

    You can print a carriage return character (\r) to move the output "cursor" back to the beginning of the current line.

    For a more sophisticated approach, take a look at something like ncurses (an API for console text-based interfaces).

    0 讨论(0)
提交回复
热议问题