Comment mettre à jour un message imprimé dans le terminal sans réimprimer (Linux)

Je veux faire une barre de progression pour mon application de terminal qui fonctionnerait quelque chose comme:

 [XXXXXXX       ] 

Ce qui donnerait une indication visuelle du temps qu'il reste avant la fin du processus.

Je sais que je peux faire quelque chose comme imprimer de plus en plus de X en les ajoutant à la chaîne, puis simplement printf, mais cela ressemblerait à:

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

Ou quelque chose comme ça (évidemment, vous pouvez jouer avec l'espacement.), Mais ce n'est pas visuellement esthétique. Est-il un moyen pour mettre à jour le texte imprimé dans un terminal avec un nouveau texte sans réimpression? Tout cela est sous linux, c++.

39
demandé sur ldog 2009-08-27 01:14:02

8 réponses

Essayez d'utiliser \r au lieu de \n lors de l'impression de la nouvelle "version".

for(int i=0;i<=100;++i) printf("\r[%3d%%]",i);
printf("\n");
43
répondu Michael Krelin - hacker 2009-08-26 21:17:51

Je dirais qu'une bibliothèque comme ncurses serait utilisé pour de telles choses. malédictions aide à déplacer le curseur autour de l'écran et dessiner du texte et autres.

NCurses

10
répondu KFro 2009-08-26 21:19:11

Quelque Chose comme ceci:

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

Le bit sournois est le caractère de retour chariot "\ r " qui fait passer le curseur au début de la ligne sans descendre à la ligne suivante.

7
répondu 1800 INFORMATION 2009-08-26 21:19:33

D'autres ont déjà fait remarquer que vous pouvez utiliser \r pour revenir au début de la ligne courante et écraser toute la ligne.

Une autre possibilité est d'utiliser le caractère de retour arrière ("\b") pour effacer quelques espaces, et écraser uniquement ces espaces. Cela peut avoir quelques avantages. Tout d'abord, il évite évidemment d'avoir à régénérer tout dans la ligne, ce qui peut parfois être légèrement douloureux (bien que ce soit assez inhabituel). Deuxièmement, il peut éviter une certaine douleur dans l'affichage les données qui (pour un exemple) rétrécissent en taille lorsque vous l'écrivez - par exemple, si vous affichez un compte à rebours de 100 à 0, avec \r Vous devez faire attention à écraser toute la longueur précédente, ou votre compte à rebours passera de (par exemple) 100 à 990 (c'est-à-dire, en laissant le "0" précédent intact).

Notez cependant que si l'espace arrière d'une ligne fonctionne normalement, un retour arrière au début d'une ligne peut ou non déplacer la position du curseur/écriture vers une ligne précédente. Pour la plupart des pratique, vous ne pouvez vous déplacer dans une seule ligne.

3
répondu Jerry Coffin 2012-06-11 15:57:32

' \ r ' effectuera un retour chariot. Imaginez une imprimante effectuant un retour chariot sans saut de ligne ('\n'). Cela ramènera le point d'écriture au début de la ligne... puis réimprimez votre statut mis à jour en haut de la ligne d'origine.

1
répondu kjfletch 2009-08-26 21:20:45

C'est une langue différente, mais cette question pourrait vous être utile. Fondamentalement, le caractère d'échappement \r (retour chariot, par opposition à \n Newline) vous ramène au début de votre ligne imprimée actuelle afin que vous puissiez écraser ce que vous avez déjà imprimé.

1
répondu Tim 2017-05-23 12:32:32

Une autre option consiste à imprimer simplement un caractère à la fois. En règle générale, stdout est mis en mémoire tampon, vous devrez donc appeler fflush (stdout) --

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

Mais cela n'a pas la belle terminaison"] " qui indique l'achèvement.

1
répondu NVRAM 2009-08-26 22:30:06

J'ai écrit cet utilitaire de barre de chargement il y a quelque temps. Pourrait être utile...

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

Vous pouvez personnaliser essentiellement n'importe quoi ici.

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;

Implémentation très simple et personnalisable..

0
répondu BlaDrzz 2018-05-24 12:38:33