C++ 如何在不重新打印的情况下更新终端中打印的消息

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1337529/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:36:52  来源:igfitidea点击:

How to update a printed message in terminal without reprinting

c++linuxtextterminal

提问by ldog

I want to make a progress bar for my terminal application that would work something like:

我想为我的终端应用程序制作一个进度条,其工作方式如下:

 [XXXXXXX       ] 

which would give a visual indication of how much time there is left before the process completes.

这将给出在过程完成之前还剩下多少时间的视觉指示。

I know I can do something like printing more and more X's by adding them to the string and then simply printf, but that would look like:

我知道我可以通过将它们添加到字符串然后简单的 printf 来打印越来越多的 X,但这看起来像:

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

or something like that (obviously you can play with the spacing.) But this is not visually aesthetic. Is there a way to update the printed text in a terminal with new text without reprinting? This is all under linux, c++.

或类似的东西(显然您可以使用间距。)但这在视觉上并不美观。有没有办法用新文本更新终端中的打印文本而无需重新打印?这都是在linux,c++下。

回答by Michael Krelin - hacker

try using \rinstead of \nwhen printing the new "version".

在打印新的“版本”时尝试使用\r而不是\n

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

回答by KFro

I'd say that a library like ncurses would be used to such things. curses helps move the cursor around the screen and draw text and such.

我会说像 ncurses 这样的库会习惯这样的事情。诅咒有助于在屏幕上移动光标并绘制文本等。

NCurses

NCurses

回答by 1800 INFORMATION

Something like this:

像这样的东西:

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

The sneaky bit is the carriage return character "\r" which causes the cursor to move to the start of the line without going down to the next line.

偷偷摸摸的位是回车符“\r”,它使光标移动到行首而不是下一行。

回答by Jerry Coffin

Others have already pointed out that you can use \rto go back to the beginning of the current line, and overwrite the entire line.

其他人已经指出,您可以使用\r返回到当前行的开头,并覆盖整行。

Another possibility is to use the backspace character ("\b") to erase a few spaces, and overwrite only those spaces. This can have a couple of advantages. First, it obviously avoids having to regenerate everything in the line, which can sometimes be mildly painful (though that is fairly unusual). Second, it can avoid some pain in displaying data that (for one example) shrinks in size as you write it -- for example, if you're displaying a count-down from 100 to 0, with \ryou have to be careful about overwriting the entire previous length, or your countdown will go from (for example) 100 to 990 (i.e., leaving the previous "0" intact).

另一种可能性是使用退格字符 ("\b") 擦除一些空格,并仅覆盖这些空格。这有几个优点。首先,它显然避免了必须重新生成线路中的所有内容,这有时会带来轻微的痛苦(尽管这很不寻常)。其次,它可以避免在显示数据时出现一些痛苦(例如)在您编写时缩小尺寸——例如,如果您显示从 100 到 0 的倒计时,\r您必须小心覆盖整个前一个长度,或者您的倒计时将从(例如)100 到 990(即,保持前一个“0”不变)。

Note, however, that while back-space within a line normally works, a backspace at the beginning of a line may or may not move the cursor/write position back to a previous line. For most practical purposes, you can only move around within a single line.

但是请注意,虽然行内的退格符通常有效,但行首的退格符可能会也可能不会将光标/写入位置移回前一行。对于大多数实际用途,您只能在一行内移动。

回答by kjfletch

'\r' will perform a carriage return. Imagine a printer doing a carriage return without a linefeed ('\n'). This will return the writing point back to the start of the line... then reprint your updated status on top of the original line.

'\r' 将执行回车。想象一下打印机在没有换行符 ('\n') 的情况下执行回车。这会将写入点返回到行的开头...然后在原始行的顶部重新打印更新的状态。

回答by Tim

It's a different language, but this questionmight be of assistance to you. Basically, the escape character \r (carriage Return, as opposed to \n Newline) moves you back to the beginning of your current printed line so you can overwrite what you've already printed.

这是一种不同的语言,但这个问题可能对你有帮助。基本上,转义字符 \r(回车,而不是 \n 换行符)将您移回到当前打印行的开头,以便您可以覆盖已经打印的内容。

回答by NVRAM

Another option is to simply print one character at a time. Typically, stdout is line buffered, so you'll need to call fflush(stdout)--

另一种选择是一次简单地打印一个字符。通常,stdout 是行缓冲的,因此您需要调用fflush(stdout)--

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

But this doesn't have the nice terminating "]" that indicates completion.

但这没有表示完成的很好的终止“]”。

回答by Jannes D.

I've written this loading bar utility some time ago. Might be useful...

我前段时间写了这个加载栏实用程序。可能有用...

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

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

You can customise basically anything in here.

你可以在这里自定义任何东西。

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;

Very simple and customisable implementation..

非常简单和可定制的实现..