Wie zeigt man eine Fortschrittsanzeige in reinem C/C++ (cout/printf) an?
Lesezeit: 6 Minuten
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?
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.
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
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.
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
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
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.
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