Ответ 1
Вы можете использовать "возврат каретки" (\ r) без строки (\n) и надеяться, что ваша консоль сделает все правильно.
Я пишу консольную программу на С++ для загрузки большого файла. Я знаю размер файла, и я запускаю рабочий поток для загрузки. Я хочу показать индикатор прогресса, чтобы он выглядел более прохладным.
Как отображать разные строки в разное время, но в том же положении, в cout или printf?
Вы можете использовать "возврат каретки" (\ r) без строки (\n) и надеяться, что ваша консоль сделает все правильно.
С фиксированной шириной вашего вывода используйте что-то вроде следующего:
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;
[> ] 0 %
[===========> ] 15 %
[======================> ] 31 %
[=================================> ] 47 %
[============================================> ] 63 %
[========================================================> ] 80 %
[===================================================================> ] 96 %
Обратите внимание, что этот вывод отображается на одной строке ниже друг друга, но в эмуляторе терминала (я думаю, также в командной строке Windows) он будет напечатан в той же строке.
В самом конце, не забудьте распечатать новую строку перед тем, как печатать больше вещей.
Если вы хотите удалить панель в конце, вы должны переписать ее пробелами, чтобы напечатать что-то более короткое, например, "Done."
.
Кроме того, то же самое можно сделать, используя printf
в C; адаптация приведенного выше кода должна быть прямой.
Для решения C
с регулируемой шириной полосы выполнения вы можете попробовать следующее:
#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);
}
Он выведет что-то вроде этого:
75% [|||||||||||||||||||||||||||||||||||||||||| ]
Взгляните на boost progress_display
http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display
Я думаю, что он может делать то, что вам нужно, и я считаю, что это библиотека только для заголовков, поэтому ничего не нужно связывать
Вы можете напечатать символ возврата каретки (\r
), чтобы переместить вывод "курсор" обратно в начало текущей строки.
Для более сложного подхода взгляните на что-то вроде ncurses (API для консольных текстовых интерфейсов).
Другим способом может быть отображение "точек" или любого другого символа, который вы хотите. Приведенный ниже код будет печатать индикатор прогресса [вид загрузки...] в виде точек каждые 1 сек.
PS: я использую сон здесь. Подумайте дважды, если производительность является проблемой.
#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;
}
Я знаю, что немного опоздал, отвечая на этот вопрос, но я сделал простой класс, который делает именно то, что вы хотите. (keep in что я написал using namespace std;
до этого.):
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
};
Пример использования:
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;
}
Примечание. Я сделал все строки классов общедоступными, чтобы внешний вид панели можно было легко изменить.
Вот простой, который я сделал:
#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 << "]";
}