2010-07-18 6 views
7

Sto codificando un monitoraggio dell'attività, che aggiorna i progressi delle attività utilizzando cout. Mi piacerebbe visualizzare un avanzamento di attività per riga, quindi devo eseguire il rollback di diverse righe della console.Come eseguire il rollback delle righe da cout?

Insisto su "diversi" perché \b esegue il lavoro per una riga, ma non cancella \n tra le righe.

Ho provato std::cout.seekp(std::cout.tellp() - str.length()); ma tellp() restituisce -1 (errore).

+2

Non è possibile. 'cout' non rappresenta la console. Rappresenta un flusso di output. Ciò significa che puoi scriverci sopra, ma non puoi fare nulla per ciò che è già stato scritto. 'cout' è per la stampa di output su qualsiasi dispositivo di output utilizzato dalla piattaforma (ad esempio, ma non necessariamente, una finestra di console). Se è necessario manipolare la console in modo specifico, è necessario utilizzare una libreria specifica del sistema operativo che conosca la finestra della console. – jalf

+1

Perché vuoi cancellare anche l'elenco delle attività completate? Basta stampare un elemento di progresso dell'attività per riga, e andrà meglio se qualcuno esegue il programma e lo stdout delle pipe in un file di registro. – jamesdlin

+0

Lo so, ma ci saranno MOLTE linee, non voglio affogare l'utente sotto le informazioni, basta dargli lo stato e il progresso percentuale di ogni attività che ho eseguito. –

risposta

16

È possibile eseguire cout << '\r'; per saltare all'inizio della riga corrente, ma lo spostamento verso l'alto è specifico del sistema. Per Unix, vedere man termcap e man terminfo (e cercare cursor_up). Sui terminali compatibili ANSI (come la maggior parte dei terminali moderni disponibili su Unix), questo funziona per spostarsi su: cout << "\e[A";.

Non provare a cercare in cout, non è consigliabile la maggior parte del tempo (tranne quando viene reindirizzato a un file).

Come menzionato in altre risposte, in base alle ncurses (o gergo) libreria fornisce una buona astrazione per il terminale I/O su Unix.

+0

Grazie, ho rinunciato a monitorare diverse righe, e ho usato \ r - riempire 79 spazi - \ r. –

8

Utilizzare una libreria di formattazione di output come ncurses se è possibile; questo semplifica notevolmente la manipolazione del terminale.

5

Né C né C++ definiscono nulla di simile. Hai bisogno di una manipolazione terminale esplicita. Su Unix puoi usare curses. Non ho idea di cosa ci sia per Windows.

1

So che questo è un vecchio post, ma l'accettato non copre i casi in cui cout è convogliato su un programma o un file e questa è la parte superiore delle mie ricerche su google. Quanto segue gestirà sia lo stdout con pipe che quello non con un comportamento leggermente diverso.

#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; 
    } 
); 

Questo non è verificato su Windows, ma dovrebbe funzionare. Quello che fa è rilevare se il descrittore di file o è un tty. Se è così, scrive "\ r" se la posizione non è cambiata dall'ultima volta che è stata stampata o una nuova riga. Se non è una nuova riga, cerca l'ultimo posto in cui si trovava dopo la stampa.

Si comporta in modo diverso per i file rispetto a tty. Per un file, se qualcosa viene esportato nello stream tra le stampe, può sovrascrivere tutto o parte di ciò che è stato scritto anche dopo le nuove righe. Per le ttys sovrascrive i caratteri all'inizio della riga corrente.

+0

vecchio ma ancora d'oro – LRP