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++.
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");
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.
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.
' \ 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.
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é.
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.
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..