C++: индикатор прогресса для консоли :)
Понадобился человеку в консольном приложении хотя бы простейший "бегунок", показывающий из цикла, какая часть расчёта выполнена (у нас шаги расчёта заменяются задержкой на 20 миллисекунд).
Вот пример простейшего класса для этой задачи и его вызова.
Предполагается, что длина бегунка всегда равна WIDTH
символов, где WIDTH
- константа класса. Она описана равной 80
символов, такова обычно ширина текстовой консоли.
В конструкторе можно указать позицию бегунка (столбец и строка экрана, счёт строк и столбцов - с левого верхнего угла начиная с единицы) и значение max
- номер максимального шага расчёта, номер первого шага всегда ноль.
Метод draw
"рисует" бегунок из символов вертикальной черты (16-ричный код 0x7C
), а go
"ставит" его в нужную позицию, выводя символы '#
' (0x23
) поверх чёрточек. Предполагается,
что go
вызывается в цикле с верхней границей max
.
Так как заголовочный файл conio.h
нестандартен для C++, работу по позиционированию курсора и выводу в консоль выполняет сторонний класс coniow
, версию coniow
, работающую со Studio 2015, можно взять
в архиве из этой заметки.
Стандартный метод round
появился только в новом стандарте C++11, поэтому
класс включает собственную реализацию округления чисел round1
. Вот полный листинг примера, проверенный в Studio 2015.
#include <cmath> #include "coniow.h" class Progress { static const int WIDTH = 80; int max,xpos,ypos,prev_ps; char cvoid, cfill; double round1(double x) { return ((x - floor(x)) >= 0.5) ? ceil(x) : floor(x); } public: Progress(int max = 100, int xpos=1, int ypos=1) { this->max = max; this->xpos = xpos; this->ypos = ypos; this->cvoid = 0x7C; this->cfill = 0x23; this->prev_ps = -1; } void draw() { gotoxy(this->xpos, this->ypos); for (int i = 1; i <= WIDTH; i++) cprintf("%c", this->cvoid); } void go(int ps) { ps = (ps < 0 ? 0 : (ps>this->max ? this->max : ps)); ps = round1(ps*(double)(WIDTH)/max); if (ps == this->prev_ps || ps<1) return; gotoxy(this->xpos, this->ypos); for (int i = 1; i <= ps; i++) cprintf("%c", this->cfill); this->prev_ps = ps; } }; int main(void) { const int n = 3456; Progress p(n); p.draw(); for (int i = 0; i<n; i++) { p.go(i); delay(20); } gotoxy(1, 2); cprintf("ok"); getch(); return 0; }
Версия подобного приложения для старых DOS-совместимых консолей могла бы выглядеть, например, так:
#include <math.h> #include <conio.h> #include <dos.h> int WIDTH =80; class Progress { int max,xpos,ypos,prev_ps; char cvoid, cfill; double round1(double x) { return ((x - floor(x)) >= 0.5) ? ceil(x) : floor(x); } public: Progress(int max = 100, int xpos=1, int ypos=1) { this->max = max; this->xpos = xpos; this->ypos = ypos; this->cvoid = 0x7C; this->cfill = 0x23; this->prev_ps = -1; } void draw() { gotoxy(this->xpos, this->ypos); for (int i = 1; i <= WIDTH; i++) cprintf("%c", this->cvoid); } void go(int ps) { ps = (ps < 0 ? 0 : (ps>this->max ? this->max : ps)); ps = round1(ps*(double)(WIDTH)/max); if (ps == this->prev_ps || ps<1) return; gotoxy(this->xpos, this->ypos); for (int i = 1; i <= ps; i++) cprintf("%c", this->cfill); this->prev_ps = ps; } }; int main(void) { const int n = 3456; clrscr(); Progress p(n); p.draw(); for (int i = 0; i<n; i++) { p.go(i); delay(10); //Make any actions here! } gotoxy(1, 2); cprintf("ok"); getch(); return 0; }
24.03.2017, 15:23 [3714 просмотров]