2010-07-18 7 views
7

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

Я настаиваю на «нескольких», потому что \b выполняет работу по одной строке, но не стирает \n между строками.

Я пробовал std::cout.seekp(std::cout.tellp() - str.length());, но tellp() возвращает -1 (отказ).

+2

Вы не можете. 'cout' не представляет консоль. Он представляет выходной поток. Это означает, что вы можете писать на него, но вы ничего не можете сделать о том, что уже написано. 'cout' предназначен для вывода вывода на печать в зависимости от того, какое устройство вывода использует платформа (например, но не обязательно, консольное окно). Если вам нужно специально управлять консолью, вам нужно использовать библиотеку, специфичную для ОС, которая знает о окне консоли. – jalf

+1

Почему вы даже хотите удалить список завершенных задач? Просто напечатайте один элемент прогресса задачи на строку, и он будет играть лучше, если кто-то запустит вашу программу, а stdout - в файл журнала. – jamesdlin

+0

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

ответ

16

Вы можете сделать cout << '\r';, чтобы перейти к началу текущей строки, но перемещение вверх зависит от системы. Для Unix см. man termcap и man terminfo (и найдите cursor_up). На терминалах, совместимых с ANSI (таких как большинство современных терминалов, доступных в Unix), это работает для продвижения вверх: cout << "\e[A";.

Не пытайтесь найти в cout, это не поддается описанию большую часть времени (кроме случаев, когда перенаправляется в файл).

Как уже упоминалось в других ответов, используя Ncurses (или жаргоне) библиотека обеспечивает хорошую абстракцию для терминала ввода/вывода на Unix.

+0

Спасибо, я бросил контроль над несколькими строками и вместо этого использовал \ r - заполнил 79 пробелов - \ r. –

8

Используйте библиотеку форматирования вывода, такую ​​как ncurses, если можете; это значительно упрощает терминальные манипуляции.

5

Ни C, ни C++ не определяют ничего подобного. Вам нужна явная манипуляция терминала. В Unix вы можете использовать curses. Не знаю, что там для Windows.

1

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

#include <iostream> 
#include <functional> 
#include <stdio.h> 

#ifdef _WIN32 
#include <io.h> 
#else 
#include <unistd.h> 
#define _isatty isatty 
#define _fileno fileno 
#endif 

const std::function<void(const size_t&)> progress_printer(_isatty(_fileno(stdout)) == 1 ? 
    [](const size_t& i) { 
     std::cout << "\rNumber " << i << std::flush; 
    } : 
    [](const size_t& i) { 
     static std::ios::off_type last(-1); 
     if(last != -1) 
      std::cout.seekp(last, std::ios::beg); 
     last = std::cout.tellp(); 
     std::cout << "Number " << i << std::endl; 
    } 
); 

Это не проверено на окнах, но должно работать. Что он делает, это определить, является ли дескриптор файла или является tty. Если это так, то он просто пишет '\ r', если pos не изменился с момента последнего его печати или новой строки. Если это не новая строка, она ищет последнее место после печати.

Это ведет себя по-разному для файлов, чем для tty. Для файла, если что-то выводит поток между отпечатками, он может перезаписать некоторые или все, что было написано даже после строк новой строки. Для ttys он просто перезаписывает символы в начале текущей строки.

+0

старый, но все еще золотой – LRP