web-dev-qa-db-fra.com

Comment afficher un indicateur de progression en C / C ++ pur (cout / printf)?

J'écris un programme de console en C++ pour télécharger un fichier volumineux. Je connais la taille du fichier et je lance un fil de travail à télécharger. Je veux montrer un indicateur de progression pour le rendre plus cool.

Comment afficher différentes chaînes à des moments différents, mais au même endroit, en cout ou en printf?

60
xmllmx

Vous pouvez utiliser un "retour chariot" (\ r) sans saut de ligne (\ n) et espérer que votre console prend les bonnes décisions.

49
James Curran

Avec une largeur fixe de votre sortie, utilisez quelque chose comme ceci:

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 %

Notez que cette sortie est affichée une ligne les unes en dessous des autres, mais dans un émulateur de terminal (je pense aussi en ligne de commande Windows), elle sera imprimée sur la même ligne .

À la toute fin, n'oubliez pas d'imprimer une nouvelle ligne avant d'imprimer plus de choses.

Si vous souhaitez supprimer la barre à la fin, vous devez la remplacer par des espaces, pour imprimer quelque chose de plus court, comme par exemple "Done.".

De même, la même chose peut évidemment être faite en utilisant printf en C; L'adaptation du code ci-dessus devrait être simple.

95
leemes

Pour une solution C avec une largeur de barre de progression réglable, vous pouvez essayer les solutions suivantes:

#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);
}

Il va sortir quelque chose comme ça:

 75% [||||||||||||||||||||||||||||||||||||||||||               ]
22
razzak

Jetez un coup d'œil à boost progress_display

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

Je pense que cela peut faire ce dont vous avez besoin et je crois que c'est une bibliothèque en-tête seulement, donc rien à relier

13
John Bandela

Vous pouvez imprimer un caractère de retour chariot (\r) pour déplacer la sortie "curseur" au début de la ligne en cours.

Pour une approche plus sophistiquée, jetez un coup d'œil à quelque chose comme ncurses (une API pour les interfaces textuelles de la console).

9
Matt Kline

Je sais que je suis un peu en retard pour répondre à cette question, mais j’ai fait n cours simple qui fait exactement ce que vous voulez. (n'oubliez pas que j’ai écrit using namespace std; avant ça.):

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
};

Un exemple sur la façon d'utiliser:

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;
}

Remarque: j'ai rendu toutes les chaînes des classes publiques afin que l'apparence de la barre puisse être facilement modifiée.

3
Flare Cat

Vous pouvez également afficher les "points" ou tout autre caractère de votre choix. Le code ci-dessous imprime l'indicateur de progression [sorte de chargement ...] sous forme de points toutes les 1 secondes.

PS: J'utilise le sommeil ici. Réfléchissez à deux fois si la performance est une préoccupation.

#include<iostream>
using namespace std;
int main()
{
    int count = 0;
    cout << "Will load in 10 Sec " << endl << "Loading ";
    for(count;count < 10; ++count){
        cout << ". " ;
        fflush(stdout);
        sleep(1);
    }
    cout << endl << "Done" <<endl;
    return 0;
}
3
A J

Voici un simple que j'ai fait:

#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
Kugel Blitz