Wie zeigt man eine Fortschrittsanzeige in reinem C/C++ (cout/printf) an?

Lesezeit: 6 Minuten

Benutzeravatar von xmllmx
xmllmx

Ich schreibe ein Konsolenprogramm in C++, um eine große Datei herunterzuladen. Ich kenne die Dateigröße und starte einen Arbeitsthread, um sie herunterzuladen. Ich möchte eine Fortschrittsanzeige zeigen, damit es cooler aussieht.

Wie kann ich verschiedene Zeichenfolgen zu unterschiedlichen Zeiten, aber an derselben Position in cout oder printf anzeigen?

  • checken Sie die PDCurses-Bibliothek aus pdcurses.sourceforge.net

    – Lefteris

    26. Januar 2013 um 18:05 Uhr


  • Die Fortschrittsanzeige der C++-Konsole könnte hilfreich sein

    – David L.

    26. Januar 2013 um 18:08 Uhr

  • Laichen a wget Prozess ist keine Option?

    – Alexander C.

    26. Januar 2013 um 18:28 Uhr

  • fluche … nfluege

    – Hippiepfad

    1. Februar 2013 um 11:15 Uhr

  • mögliches Duplikat von Rewinding std::cout , um zum Anfang einer Zeile zurückzukehren

    – kiranpradeep

    12. Juni 2015 um 8:52 Uhr

Benutzeravatar von leemes
leemes

Verwenden Sie bei einer festen Breite Ihrer Ausgabe etwa Folgendes:

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 %

Beachten Sie, dass diese Ausgabe ist gezeigt eine Zeile untereinander, aber in einem Terminal-Emulator (ich glaube auch in der Windows-Befehlszeile) wird es gedruckt auf der gleichen Linie.

Vergessen Sie ganz am Ende nicht, einen Zeilenumbruch zu drucken, bevor Sie mehr Zeug drucken.

Wenn Sie den Balken am Ende entfernen möchten, müssen Sie ihn mit Leerzeichen überschreiben, um z. B. etwas Kürzeres zu drucken "Done.".

Dasselbe kann natürlich auch mit gemacht werden printf in C; Das Anpassen des obigen Codes sollte einfach sein.

Benutzeravatar von James Curran
James Curran

Sie können einen “Wagenrücklauf” (\r) ohne Zeilenvorschub (\n) verwenden und hoffen, dass Ihre Konsole das Richtige tut.

  • + manuelles Spülen, sonst wird es nicht sofort angezeigt, da die Ausgabe gepuffert wird.

    – leemes

    26. Januar 2013 um 18:06 Uhr

  • Und wenn der Benutzer versehentlich die Eingabetaste drückt, bricht es zusammen 🙁 Abgesehen davon ist es vielleicht die portabelste Lösung, +1.

    – Ali

    26. Januar 2013 um 19:00 Uhr


  • @Ali Um dies zu vermeiden, müssten Sie das Echo deaktivieren (siehe man termios)

    – leemes

    26. Januar 2013 um 23:27 Uhr


  • @leemes #include <termios.h>versuchen Sie das unter M$ Windows 🙂 Wie auch immer, danke für den Tipp, ich werde das wahrscheinlich unter Linux versuchen.

    – Ali

    27. Januar 2013 um 8:47 Uhr

  • @Ali Möglicherweise gibt es ein Äquivalent für W1ndOw $, aber ich weiß es nicht. 😉

    – leemes

    27. Januar 2013 um 14:00 Uhr

Benutzeravatar von razz
rasieren

Für ein C Lösung mit einstellbarer Fortschrittsbalkenbreite können Sie Folgendes verwenden:

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

Es wird ungefähr so ​​​​ausgeben:

 75% [||||||||||||||||||||||||||||||||||||||||||               ]

  • Achtung, es sollte keine geben ';' am Ende des ersten #define!

    – Robb1

    6. Mai 2017 um 9:01 Uhr

  • Dies ist die einfachste und beste Lösung, die ich bisher gefunden habe

    – gruselig

    23. November 2017 um 8:03 Uhr

  • Gibt es eine Möglichkeit, anstelle von | ein ASCII-Zeichen anzuzeigen? ? Vielen Dank

    – momo123

    2. März 2020 um 17:17 Uhr

  • Was bedeutet der letzte Teil, warum gibt es a "" für das letzte Argument der printf() ?

    – Sylvain

    30. April 2021 um 13:42 Uhr

  • @Sylvain Die Zeichenfolge in den eckigen Klammern besteht aus zwei Teilen; links und rechts. Der linke Teil besteht aus lpad Zeichen von PBSTR gedruckt mit der %.*s Bezeichner, während der rechte Teil aus besteht rpad Länge eines mit Leerzeichen aufgefüllten Strings, den wir als leer gewählt haben “”, damit wir nur drucken rpad Leerzeichen mit der %*s Bezeichner.

    – rasieren

    1. Mai 2021 um 2:37 Uhr


Schauen Sie sich boost progress_display an

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

Ich denke, es kann das tun, was Sie brauchen, und ich glaube, es ist nur eine Header-Bibliothek, also nichts zu verlinken

Sie können ein Wagenrücklaufzeichen (\r), um den Ausgabe-“Cursor” zurück an den Anfang der aktuellen Zeile zu bewegen.

Für einen anspruchsvolleren Ansatz werfen Sie einen Blick auf etwas wie ncurses (eine API für textbasierte Konsolenschnittstellen).

  • + manuelles Spülen, sonst wird es nicht sofort angezeigt, da die Ausgabe gepuffert wird.

    – leemes

    26. Januar 2013 um 18:07 Uhr

  • + '\b' zum Verschieben des Cursors um eine Position nach links.

    – Alexey Frunze

    26. Januar 2013 um 18:10 Uhr

  • +1 für Ncurses. Definitiv der richtige Weg, wenn Sie etwas Komplexeres machen möchten.

    – Löwe

    27. Januar 2013 um 9:11 Uhr

Benutzeravatar von Flare Cat
Flare-Katze

Ich weiß, dass ich mit der Beantwortung dieser Frage etwas spät bin, aber ich habe es geschafft eine einfache Klasse, die genau das tut, was Sie wollen. (Denken Sie daran, dass ich geschrieben habe using namespace std; vor dem.):

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

Ein Anwendungsbeispiel:

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

Hinweis: Ich habe alle Zeichenfolgen der Klassen öffentlich gemacht, damit das Aussehen der Leiste leicht geändert werden kann.

  • + manuelles Spülen, sonst wird es nicht sofort angezeigt, da die Ausgabe gepuffert wird.

    – leemes

    26. Januar 2013 um 18:07 Uhr

  • + '\b' zum Verschieben des Cursors um eine Position nach links.

    – Alexey Frunze

    26. Januar 2013 um 18:10 Uhr

  • +1 für Ncurses. Definitiv der richtige Weg, wenn Sie etwas Komplexeres machen möchten.

    – Löwe

    27. Januar 2013 um 9:11 Uhr

Benutzeravatar von genpfault
Genpfault

Eine andere Möglichkeit könnte darin bestehen, die “Punkte” oder ein beliebiges Zeichen anzuzeigen. Der folgende Code druckt eine Fortschrittsanzeige [sort of loading…]als Punkte alle nach 1 Sek.

PS: Ich verwende hier Schlaf. Denken Sie zweimal nach, wenn es um Leistung geht.

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

1420760cookie-checkWie zeigt man eine Fortschrittsanzeige in reinem C/C++ (cout/printf) an?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy