2009-08-26 6 views
37

Voglio fare una barra di avanzamento per la mia applicazione terminale che avrebbe funzionato qualcosa come:come aggiornare un messaggio stampato nel terminale senza ristampa (Linux)

[XXXXXXX  ] 

che darebbe un'indicazione visiva di quanto tempo c'è rimasto prima che il processo sia completato.

So che posso fare qualcosa di simile la stampa sempre più X di aggiungendoli alla stringa e poi semplicemente printf, ma che sarà simile:

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

o qualcosa del genere (ovviamente si può giocare con la spaziatura.) Ma questo non è visivamente estetico. C'è un modo per aggiornare il testo stampato in un terminale con un nuovo testo senza ristamparlo? Questo è tutto sotto Linux, C++.

risposta

40

provare a utilizzare \r anziché \n quando si stampa la nuova "versione".

for(int i=0;i<=100;++i) printf("\r[%3d%%]",i); 
printf("\n"); 
+0

funziona come un incantesimo, grazie – ldog

8

Direi che una libreria come ncurses sarebbe utilizzata per queste cose. curses aiuta a spostare il cursore sullo schermo e disegnare il testo e così via.

NCurses

+6

Suona come un overkill qui. –

+1

Sì, probabilmente ... solo un suggerimento se qualcuno vuole avere più fantasia in futuro;) – KFro

+3

Sì ... potrebbe esserci una partita di PONG in corso mentre aspettiamo la barra di avanzamento. : D – kjfletch

6

Qualcosa di simile a questo:

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

L'po 'subdolo è il carattere di ritorno a capo "\ r", che provoca il cursore per spostare l'inizio della linea senza andare fino alla prossima linea.

1

'\ r' eseguirà un ritorno a capo. Immagina una stampante che esegue un ritorno a capo senza un linefeed ('\ n'). Ciò restituirà il punto di scrittura all'inizio della riga ... quindi ristamperà lo stato aggiornato sopra la riga originale.

1

È una lingua diversa, ma this question potrebbe essere di aiuto per voi. Fondamentalmente, il carattere di escape \ r (carriage Return, al contrario di \ n Newline) ti riporta all'inizio della linea stampata corrente in modo da poter sovrascrivere quello che hai già stampato.

1

Un'altra opzione è semplicemente stampare un carattere alla volta. In genere, stdout è la linea tamponato, quindi avrai bisogno di chiamare fflush (stdout) -

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

Ma questo non ha la bella di terminazione "]" che indica il completamento.

3

Altri hanno già sottolineato che è possibile utilizzare \r per tornare all'inizio della riga corrente e sovrascrivere l'intera riga.

Un'altra possibilità è utilizzare il carattere backspace ("\ b") per cancellare alcuni spazi e sovrascrivere solo quegli spazi. Questo può avere un paio di vantaggi. In primo luogo, evita ovviamente di dover rigenerare tutto nella linea, che a volte può essere lievemente doloroso (anche se è abbastanza inusuale). In secondo luogo, può evitare un po 'di dolore nel visualizzare i dati che (per un esempio) si restringono di dimensioni mentre lo scrivi - ad esempio, se stai visualizzando un conto alla rovescia da 100 a 0, con \r devi stare attento a sovrascrivendo l'intera lunghezza precedente, o il conto alla rovescia passerà (per esempio) da 100 a 990 (cioè lasciando intatto lo "0" precedente).

Si noti tuttavia che, mentre lo spazio di ritorno all'interno di una linea normalmente funziona, un backspace all'inizio di una riga può o meno spostare la posizione del cursore/scrittura su una riga precedente. Per scopi pratici, puoi muoverti solo all'interno di una singola riga.