我正在用C++编写一个控制台程序来下载一个大文件。我知道文件大小,我启动一个工作线程来下载它。我想显示一个进度指示器,使其看起来更酷。
如何在不同时间显示不同的字符串,但在同一位置,在 cout 或 printf 中?
对于输出的固定宽度,请使用如下所示的内容:
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
来完成同样的事情;调整上面的代码应该是直截了当的。
您可以使用不带换行符 () 的"回车符"(\r),并希望您的控制台做正确的事情。
对于具有可调整进度条宽度的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% [|||||||||||||||||||||||||||||||||||||||||| ]
看看提升progress_display
http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display
我认为它可以满足您的需求,我相信它是一个仅标题库,因此无需链接
您可以打印回车符 ( r
) 将输出"光标"移回当前行的开头。
对于更复杂的方法,请查看 ncurses(用于控制台基于文本的界面的 API)之类的内容。
我回答这个问题有点晚了,但我做了一个简单的类,完全可以满足你的要求。(请记住,我在此之前写过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;
}
注意:我公开了所有类的字符串,以便可以轻松更改栏的外观。
另一种方式可能是显示"点"或您想要的任何字符。下面的代码将打印进度指示器 [加载方式...]每 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;
}
这是我做的一个简单的:
#include <iostream>
#include <thread>
#include <chrono>
#include <Windows.h>
using namespace std;
int main() {
// Changing text color (GetStdHandle(-11), colorcode)
SetConsoleTextAttribute(GetStdHandle(-11), 14);
int barl = 20;
cout << "[";
for (int i = 0; i < barl; i++) {
this_thread::sleep_for(chrono::milliseconds(100));
cout << ":";
}
cout << "]";
// Reset color
SetConsoleTextAttribute(GetStdHandle(-11), 7);
}
我非常简单的 C 解决方案:
#include <stdio.h>
#define S_(x) #x
#define S(x) S_(x)
#define PBWIDTH 64
#define PBCHAR '#'
static void progressbar(unsigned percent) {
char pbstr[PBWIDTH];
memset(pbstr, PBCHAR, PBWIDTH);
fprintf(stderr, "r[%-" S(PBWIDTH) ".*s] %u%%",
percent * PBWIDTH / 100, pbstr, percent);
}
int main(void) {
progressbar(70);
fprintf(stderr, "n");
}
输出:
[############################################ ] 70%
当针对现代 CPU 编译时,memset
应优化为 1 或 2 个矢量指令,比静态存储整个字符串要小得多,而且速度相同。
在我使用它的程序中,我喜欢以这种方式打印 0%,在调用 progressbar
的循环之前:
fprintf(stderr, "[%-" S(PBWIDTH) ".*s] %u%%", 0, "", 0);
<小时 />如果您希望数字位于条形之前,请更改progressbar
中的fprintf
:
fprintf(stderr, "r%3u%% [%-" S(PBWIDTH) ".*s]",
percent, percent * PBWIDTH / 100, pbstr);
如果您执行可选的 0% 位:
fprintf(stderr, "%3u%% [%-" S(PBWIDTH) ".*s]", 0, 0, "");
根据需要修改所有内容。 :)
也许这段代码会帮助你 -
#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 << "nn";
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 << "nn";
}
int main()
{
show_progress_bar(100, "progress" , '#');
}
很简单,你可以使用string的fill构造函数:
#include <iostream> //for `cout`
#include <string> //for the constructor
#include <iomanip> //for `setprecision`
using namespace std;
int main()
{
const int cTotalLength = 10;
float lProgress = 0.3;
cout <<
"r[" << //'r' aka carriage return should move printer's cursor back at the beginning of the current line
string(cTotalLength * lProgress, 'X') << //printing filled part
string(cTotalLength * (1 - lProgress), '-') << //printing empty part
"] " <<
setprecision(3) << 100 * lProgress << "%"; //printing percentage
return 0;
}
这将打印:
[XXX-------] 30%
如果你在纯C中需要它
并且您希望能够在运行时自定义大小和填充字符:
#include <stdio.h> //for `printf`
#include <stdlib.h> //for `malloc`
#include <string.h> //for `memset`
int main()
{
const int cTotalLength = 10;
char* lBuffer = malloc((cTotalLength + 1) * sizeof *lBuffer); //array to fit 10 chars + ' '
lBuffer[cTotalLength] = ' '; //terminating it
float lProgress = 0.3;
int lFilledLength = lProgress * cTotalLength;
memset(lBuffer, 'X', lFilledLength); //filling filled part
memset(lBuffer + lFilledLength, '-', cTotalLength - lFilledLength); //filling empty part
printf("r[%s] %.1f%%", lBuffer, lProgress * 100); //same princip as with the CPP method
//or you can combine it to a single line if you want to flex ;)
//printf("r[%s] %.1f%%", (char*)memset(memset(lBuffer, 'X', lFullLength) + lFullLength, '-', cTotalLength - lFullLength) - lFullLength, lProgress * 100);
free(lBuffer);
return 0;
}
但是,如果您不需要在运行时自定义它:
#include <stdio.h> //for `printf`
#include <stddef.h> //for `size_t`
int main()
{
const char cFilled[] = "XXXXXXXXXX";
const char cEmpty[] = "----------";
float lProgress = 0.3;
size_t lFilledStart = (sizeof cFilled - 1) * (1 - lProgress);
size_t lEmptyStart = (sizeof cFilled - 1) * lProgress;
printf("r[%s%s] %.1f%%",
cFilled + lFilledStart, //Array of Xs starting at `cTotalLength * (1 - lProgress)` (`cTotalLength * lProgress` characters remaining to EOS)
cEmpty + lEmptyStart, //Array of -s starting at `cTotalLength * lProgress`...
lProgress * 100 //Percentage
);
return 0;
}
我需要创建一个进度条,这里的一些答案会导致进度条闪烁或在完成后显示 100% 的缺失百分比。这是一个除了模拟 cpu 工作的版本之外没有循环的版本,它仅在下一个进度单元递增时打印。
#include <iostream>
#include <iomanip> // for setw, setprecision, setfill
#include <chrono>
#include <thread> // simulate work on cpu
int main()
{
int batch_size = 4000;
int num_bars = 50;
int batch_per_bar = batch_size / num_bars;
int progress = 0;
for (int i = 0; i < batch_size; i++) {
if (i % batch_per_bar == 0) {
std::cout << std::setprecision(3) <<
// fill bar with = up to current progress
'[' << std::setfill('=') << std::setw(progress) << '>'
// fill the rest of the bar with spaces
<< std::setfill(' ') << std::setw(num_bars - progress + 1)
// display bar percentage, r brings it back to the beginning
<< ']' << std::setw(3) << ((i + 1) * 100 / batch_size) << '%'
<< "r";
progress++;
}
// simulate work
std::this_thread::sleep_for(std::chrono::nanoseconds(1000000));
}
}