如何在纯 C/C++ (cout/printf) 中显示进度指示器?
Posted
技术标签:
【中文标题】如何在纯 C/C++ (cout/printf) 中显示进度指示器?【英文标题】:How to display a progress indicator in pure C/C++ (cout/printf)? 【发布时间】:2013-01-10 11:35:30 【问题描述】:我正在用 C++ 编写一个控制台程序来下载一个大文件。我知道文件大小,我启动了一个工作线程来下载它。我想显示一个进度指示器,让它看起来更酷。
如何在 cout 或 printf 中,在不同的时间,但在相同的位置显示不同的字符串?
【问题讨论】:
查看 PDCurses 库 pdcurses.sourceforge.net C++ Console Progress Indicator 可能会有所帮助 不能生成wget
进程?
curses ... ncurses
Rewinding std::cout to go back to the beginning of a line的可能重复
【参考方案1】:
使用固定宽度的输出,使用如下内容:
float progress = 0.0;
while (progress < 1.0)
int barWidth = 70;
std::cout << "[";
int pos = barWidth * progress;
for (int i = 0; i < barWidth; ++i)
if (i < pos) std::cout << "=";
else if (i == pos) std::cout << ">";
else std::cout << " ";
std::cout << "] " << int(progress * 100.0) << " %\r";
std::cout.flush();
progress += 0.16; // for demonstration only
std::cout << std::endl;
http://ideone.com/Yg8NKj
[> ] 0 %
[===========> ] 15 %
[======================> ] 31 %
[=================================> ] 47 %
[============================================> ] 63 %
[========================================================> ] 80 %
[===================================================================> ] 96 %
请注意,此输出显示在彼此下方一行,但在终端仿真器中(我认为也是在 Windows 命令行中),它将在同一行上打印.
最后,不要忘记在打印更多内容之前打印一个换行符。
如果你想删除最后的栏,你必须用空格覆盖它,以打印更短的东西,例如"Done."
。
同样,当然可以在 C 中使用 printf
来完成相同的操作;修改上面的代码应该是直截了当的。
【讨论】:
【参考方案2】:您可以使用不带换行符 (\n) 的“回车”(\r),并希望您的控制台做正确的事情。
【讨论】:
+ 手动刷新,否则不会立即显示,因为输出是缓冲的。 如果用户不小心按了回车键,它就会崩溃:(除此之外,它可能是最便携的解决方案,+1。 @Ali 为避免这种情况,您必须禁用回显(请参阅man termios
)
@leemes #include <termios.h>
,在 M$ Windows 上试试 :) 无论如何,谢谢你的提示,我可能会在 Linux 上试试。
@Ali W1ndOw$ 可能有等价物,但我不知道。 ;)【参考方案3】:
对于具有可调节进度条宽度的C
解决方案,您可以使用以下内容:
#define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
#define PBWIDTH 60
void printProgress(double percentage)
int val = (int) (percentage * 100);
int lpad = (int) (percentage * PBWIDTH);
int rpad = PBWIDTH - lpad;
printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, "");
fflush(stdout);
它会输出如下内容:
75% [|||||||||||||||||||||||||||||||||||||||||| ]
【讨论】:
注意,第一个#define
的末尾应该没有';'
!
这是迄今为止我找到的最简单最好的解决方案
有没有办法显示 ascii 字符而不是 | ?谢谢
最后一部分是什么意思,为什么printf()
的最后一个参数有""
?
@Sylvain 方括号中的字符串有两部分;左和右。左边部分由PBSTR
的lpad
字符组成,使用%.*s
说明符打印,而右边部分由rpad
空格左填充字符串的长度组成,我们选择为空“”,这样我们只使用 %*s
说明符打印 rpad
空格。【参考方案4】:
看看 boost progress_display
http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display
我认为它可以满足您的需求,并且我相信它是一个仅标头库,因此无需链接
【讨论】:
【参考方案5】:您可以打印回车符 (\r
) 将输出“光标”移回当前行的开头。
要了解更复杂的方法,请查看 ncurses(基于控制台文本的界面的 API)之类的东西。
【讨论】:
+ 手动刷新,否则不会立即显示,因为输出是缓冲的。 +'\b'
将光标向左移动一位。
ncurses 为 +1。如果您想做一些更复杂的事情,绝对是要走的路。【参考方案6】:
我知道我回答这个问题有点晚了,但我写了a simple class that does exactly what you want.(请记住,我在此之前写了using namespace std;
。):
class pBar
public:
void update(double newProgress)
currentProgress += newProgress;
amountOfFiller = (int)((currentProgress / neededProgress)*(double)pBarLength);
void print()
currUpdateVal %= pBarUpdater.length();
cout << "\r" //Bring cursor to start of line
<< firstPartOfpBar; //Print out first part of pBar
for (int a = 0; a < amountOfFiller; a++) //Print out current progress
cout << pBarFiller;
cout << pBarUpdater[currUpdateVal];
for (int b = 0; b < pBarLength - amountOfFiller; b++) //Print out spaces
cout << " ";
cout << lastPartOfpBar //Print out last part of progress bar
<< " (" << (int)(100*(currentProgress/neededProgress)) << "%)" //This just prints out the percent
<< flush;
currUpdateVal += 1;
std::string firstPartOfpBar = "[", //Change these at will (that is why I made them public)
lastPartOfpBar = "]",
pBarFiller = "|",
pBarUpdater = "/-\\|";
private:
int amountOfFiller,
pBarLength = 50, //I would recommend NOT changing this
currUpdateVal = 0; //Do not change
double currentProgress = 0, //Do not change
neededProgress = 100; //I would recommend NOT changing this
;
使用示例:
int main()
//Setup:
pBar bar;
//Main loop:
for (int i = 0; i < 100; i++) //This can be any loop, but I just made this as an example
//Update pBar:
bar.update(1); //How much new progress was added (only needed when new progress was added)
//Print pBar:
bar.print(); //This should be called more frequently than it is in this demo (you'll have to see what looks best for your program)
sleep(1);
cout << endl;
return 0;
注意:我公开了所有类的字符串,以便可以轻松更改栏的外观。
【讨论】:
【参考方案7】:另一种方式可能是显示“点”或您想要的任何字符。下面的代码将每隔 1 秒将进度指示器 [加载的排序...]打印为点。
PS:我在这里使用睡眠。如果担心性能,请三思。
#include<iostream>
using namespace std;
int main()
int count = 0;
cout << "Will load in 10 Sec " << endl << "Loading ";
for(count;count < 10; ++count)
cout << ". " ;
fflush(stdout);
sleep(1);
cout << endl << "Done" <<endl;
return 0;
【讨论】:
【参考方案8】:这是我做的一个简单的:
#include <iostream>
#include <windows.h>
using namespace std;
int barl = 20;
int main()
system("color 0e");
cout << "[";
for (int i = 0; i < barl; i++)
Sleep(100);
cout << ":";
cout << "]";
【讨论】:
【参考方案9】:也许这段代码会对你有所帮助 -
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <cmath>
using namespace std;
void show_progress_bar(int time, const std::string &message, char symbol)
std::string progress_bar;
const double progress_level = 1.42;
std::cout << message << "\n\n";
for (double percentage = 0; percentage <= 100; percentage += progress_level)
progress_bar.insert(0, 1, symbol);
std::cout << "\r [" << std::ceil(percentage) << '%' << "] " << progress_bar;
std::this_thread::sleep_for(std::chrono::milliseconds(time));
std::cout << "\n\n";
int main()
show_progress_bar(100, "progress" , '#');
【讨论】:
以上是关于如何在纯 C/C++ (cout/printf) 中显示进度指示器?的主要内容,如果未能解决你的问题,请参考以下文章
在cin / cout和scanf / printf期间在C ++中保存float和double precision