Как отобразить индикатор выполнения в чистом C / C++ (cout/printf)?



Я пишу консольную программу на C++ для загрузки большого файла. Я знаю размер файла, и я начинаю рабочий поток для загрузки. Я хочу показать индикатор прогресса, чтобы он выглядел круче.



Как отображать разные строки в разное время, но в одной и той же позиции, в cout или printf?

748   8  

8 ответов:

вы можете использовать "возврат каретки" (\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;

http://ideone.com/Yg8NKj

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

Я знаю, что немного опоздал с ответом на этот вопрос, но я сделал простой класс, который делает именно то, что вы хотите. (имейте в виду, что я писал 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;
}

Примечание: я сделал все строки классов общедоступными, поэтому внешний вид бара можно легко изменить.

вот простой, который я сделал: D

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

Comments

    Ничего не найдено.