Как обновить печатное сообщение в терминале без перепечатки - PullRequest
39 голосов
/ 27 августа 2009

Я хочу сделать индикатор выполнения для моего терминального приложения, который бы работал примерно так:

 [XXXXXXX       ] 

, который наглядно показывает, сколько времени осталось до завершения процесса.

Я знаю, что могу сделать что-то вроде печати все большего и большего количества X, добавив их в строку, а затем просто напечатав printf, но это будет выглядеть так:

 [XXXXXXX       ] 
 [XXXXXXXX      ] 
 [XXXXXXXXX     ] 
 [XXXXXXXXXX    ] 

или что-то в этом роде (очевидно, вы можете играть с интервалом.) Но это не визуально эстетично. Есть ли способ обновить напечатанный текст в терминале новым текстом без перепечатки? Это все под Linux, C ++.

Ответы [ 8 ]

43 голосов
/ 27 августа 2009

попробуйте использовать \r вместо \n при печати новой "версии".

for(int i=0;i<=100;++i) printf("\r[%3d%%]",i);
printf("\n");
10 голосов
/ 27 августа 2009

Я бы сказал, что для таких вещей будет использоваться библиотека, подобная ncurses curses помогает перемещать курсор по экрану и рисовать текст и тому подобное.

Ncurses

7 голосов
/ 27 августа 2009

Примерно так:

std::stringstream out;
for (int i = 0; i< 10; i++)
{
  out << "X";
  cout << "\r" << "[" << out.str() << "]";
}

Скрытый бит - это символ возврата каретки "\ r", который заставляет курсор перемещаться в начало строки без перехода к следующей строке.

3 голосов
/ 11 июня 2012

Другие уже указали, что вы можете использовать \r, чтобы вернуться к началу текущей строки и перезаписать всю строку.

Другая возможность - использовать символ возврата («\ b») для удаления нескольких пробелов и перезаписи только этих пробелов. Это может иметь пару преимуществ. Во-первых, он, очевидно, избегает необходимости восстанавливать все в строке, что иногда может быть слегка болезненным (хотя это довольно необычно). Во-вторых, это может избежать некоторой боли при отображении данных, которые (для одного примера) уменьшаются в размере по мере их написания - например, если вы отображаете обратный отсчет от 100 до 0, при \r вы должны быть будьте внимательны с перезаписью всей предыдущей длины, иначе обратный отсчет переместится с (например) 100 на 990 (т. е. оставив прежний «0» без изменений).

Обратите внимание, однако, что хотя обратный пробел в строке обычно работает, возврат в начале строки может или не может переместить курсор / позицию записи назад к предыдущей строке. В большинстве практических целей вы можете перемещаться только в пределах одной строки.

1 голос
/ 27 августа 2009

Другой вариант - просто печатать по одному символу за раз. Обычно stdout является буферизованной строкой, поэтому вам нужно вызвать fflush (stdout) -

for(int i = 0; i < 50; ++i) {
   putchar('X'); fflush(stdout);
   /* do some stuff here */
}
putchar('\n');

Но у этого нет хорошего завершающего "]", который указывает на завершение.

1 голос
/ 27 августа 2009

Это другой язык, но этот вопрос может быть вам полезен. По сути, escape-символ \ r (возврат каретки, в отличие от \ n новой строки) возвращает вас к началу текущей напечатанной строки, поэтому вы можете перезаписать то, что уже напечатали.

1 голос
/ 27 августа 2009

'\ r' выполнит возврат каретки. Представьте, что принтер выполняет возврат каретки без перевода строки ('\ n'). Это вернет точку записи обратно в начало строки ... затем перепечатает ваш обновленный статус поверх исходной строки.

0 голосов
/ 24 мая 2018

Я написал эту утилиту загрузки бар некоторое время назад. Может быть полезно ...

https://github.com/BlaDrzz/CppUtility/tree/master/LoadingBar

Здесь можно настроить практически все, что угодно.

int max = 1000;
LoadingBar* lb = new LoadingBar(10, 0, max);

for (size_t i = 0; i <= max; i++)
{
    lb->print();
    lb->iterate();
}
cout << lb->toString() << endl;

Очень простая и настраиваемая реализация ..

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...