Come aggiornare un messaggio stampato nel terminale senza ristampare (Linux)

Voglio creare una barra di avanzamento per la mia applicazione terminale che funzioni in qualche modo:

[XXXXXXX ] 

che darebbe un’indicazione visiva di quanto tempo rimane prima del completamento del processo.

So che posso fare qualcosa come stampare sempre più X aggiungendoli alla stringa e quindi semplicemente printf, ma che assomiglierebbe a:

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

o qualcosa del genere (ovviamente puoi 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 ++.

prova a usare \r invece di \n quando stampi la nuova “versione”.

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

Direi che una biblioteca come ncurses sarebbe abituata a cose del genere. curses aiuta a spostare il cursore sullo schermo e disegnare il testo e così via.

NCurses

Qualcosa come questo:

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

Il bit nascosto è il carattere di ritorno a capo "\ r" che fa muovere il cursore all'inizio della riga senza passare alla riga successiva.

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

Un’altra possibilità è usare 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, devi essere attento circa la sovrascrittura dell’intera lunghezza precedente, o il conto alla rovescia andrà da (per esempio) 100 a 990 (cioè, lasciando il precedente “0” intatto).

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.

‘\ 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.

È una lingua diversa, ma questa domanda potrebbe esserti d’aiuto. 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.

Un’altra opzione è semplicemente stampare un carattere alla volta. In genere, lo stdout ha una linea bufferizzata, quindi dovrai chiamare fflush (stdout)

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

Ma questo non ha il simpatico termine "]" che indica il completamento.

Ho scritto questa utility della barra di caricamento qualche tempo fa. Potrebbe essere utile …

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

Puoi personalizzare praticamente qualsiasi cosa qui.

 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; 

Implementazione molto semplice e personalizzabile ..