如何在不重新打印的情况下更新终端中的打印消息
Posted
技术标签:
【中文标题】如何在不重新打印的情况下更新终端中的打印消息【英文标题】:How to update a printed message in terminal without reprinting 【发布时间】:2010-11-23 04:16:46 【问题描述】:我想为我的终端应用程序制作一个进度条,其工作方式如下:
[XXXXXXX ]
这将直观地指示在该过程完成之前还剩下多少时间。
我知道我可以通过将它们添加到字符串中然后简单地 printf 来打印越来越多的 X,但这看起来像:
[XXXXXXX ]
[XXXXXXXX ]
[XXXXXXXXX ]
[XXXXXXXXXX ]
或类似的东西(显然你可以使用间距。)但这在视觉上并不美观。有没有办法在不重新打印的情况下用新文本更新终端中的打印文本?这都是在linux、c++下的。
【问题讨论】:
【参考方案1】:在打印新的“版本”时尝试使用\r
而不是\n
。
for(int i=0;i<=100;++i) printf("\r[%3d%%]",i);
printf("\n");
【讨论】:
【参考方案2】:我会说像 ncurses 这样的库将用于此类事情。 curses 帮助在屏幕上移动光标并绘制文本等。
NCurses
【讨论】:
这里听起来有点矫枉过正。 是的,可能......如果有人想在未来变得更花哨,这只是一个建议;) 是的...在我们等待进度条时,可能会进行 PONG 游戏。 :D 谢谢你的提示;)我知道 ncurses,我以前用它来制作终端刽子手游戏,但我想在使用它之前问问周围,因为我知道它是矫枉过正【参考方案3】:类似这样的:
std::stringstream out;
for (int i = 0; i< 10; i++)
out << "X";
cout << "\r" << "[" << out.str() << "]";
偷偷摸摸的位是回车符“\r”,它使光标移动到行首而不下一行。
【讨论】:
【参考方案4】:其他人已经指出,你可以使用\r
回到当前行的开头,并覆盖整行。
另一种可能性是使用退格符(“\b”)删除一些空格,并仅覆盖这些空格。这可以有几个优点。首先,它显然避免了必须重新生成行中的所有内容,这有时会带来轻微的痛苦(尽管这是相当不寻常的)。其次,它可以避免在显示数据时(例如)在写入时缩小的数据的一些痛苦——例如,如果您要显示从 100 到 0 的倒计时,\r
您必须是小心覆盖之前的整个长度,否则您的倒计时将从(例如)100 变为 990(即,保持之前的“0”不变)。
但是请注意,虽然行内的退格正常工作,但行首的退格可能会也可能不会将光标/写入位置移回前一行。对于大多数实际用途,您只能在一行内移动。
【讨论】:
【参考方案5】:'\r' 将执行回车。想象一下打印机在没有换行符('\n')的情况下执行回车。这会将写入点返回到行首...然后在原始行的顶部重新打印您的更新状态。
【讨论】:
【参考方案6】:这是一种不同的语言,但this question 可能会对您有所帮助。基本上,转义字符 \r(回车,而不是 \n 换行符)将您移回当前打印行的开头,以便您可以覆盖已经打印的内容。
【讨论】:
【参考方案7】:另一种选择是一次只打印一个字符。通常,stdout 是行缓冲的,因此您需要调用 fflush(stdout) --
for(int i = 0; i < 50; ++i)
putchar('X'); fflush(stdout);
/* do some stuff here */
putchar('\n');
但这没有表示完成的漂亮终止“]”。
【讨论】:
【参考方案8】:我前段时间写过这个加载栏实用程序。可能有用...
https://github.com/BlaDrzz/CppUtility/tree/master/LoadingBar
你基本上可以在这里自定义任何东西。
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;
非常简单和可定制的实现..
【讨论】:
以上是关于如何在不重新打印的情况下更新终端中的打印消息的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在不使用 python 移动终端行的情况下在同一位置打印“for循环”表?
如何在不显示打印对话框的情况下使用 JRPrintServiceExporter 更改边距?