我正在用 C++ 写一个控制台程序来下载一个大文件。我知道文件的大小,并且开了一个工作线程来下载它。我想显示一个进度指示器,使它看起来更酷。
如何在 cout 或 printf 中同一位置不同时显示不同的字符串?
我正在用 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;
[> ] 0 %
[===========> ] 15 %
[======================> ] 31 %
[=================================> ] 47 %
[============================================> ] 63 %
[========================================================> ] 80 %
[===================================================================> ] 96 %
请注意,这个输出会在每一行下面显示,但是在终端仿真器(我认为在Windows命令行中也是如此)中,它将被打印在同一行上。"完成。"
。printf
来完成同样的操作;调整上面的代码应该很容易。要创建一个具有可调进度条宽度的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
结尾处不应该有;
! - Robb1%.*s
格式说明符打印的PBSTR
字符的lpad
长度组成,而右边部分则由我们选择为空字符串""的左填充字符串的rpad
长度组成,以便我们只使用%*s
格式说明符打印rpad
个空格。 - razz#include <termios.h>
,在M$ Windows上试试看吧 :) 不管怎样,感谢你的建议,我可能会在Linux上尝试一下。 - Ali"\r\e[0K"
也可以帮助清除行。 (在Linux下测试) - YuMS您可以打印回车符(\r
)将输出“光标”移回当前行的开头。
若要更高级的方法,请查看类似于ncurses(用于文本界面控制台的API)的东西。
'\b'
用于将光标向左移动一个位置。看一下boost progress_display
http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display
我认为它可能做到你需要的,并且我相信它是一个仅包含头文件的库,所以不需要链接任何东西。
我知道我有点晚回答这个问题,但是我制作了一个简单的类,可以实现你想要的功能。(请记住,在此之前我写了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;
}
#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);
}
SetConsoleTextAttribute(hConsole, color)
,并别忘了重置(颜色7)。 - Felierix#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%
memset
在编译为现代CPU时应该进行优化,可以使用1或2个向量指令,比静态存储整个字符串要小得多,速度也一样快。
在我使用的程序中,在调用progressbar
的循环之前,我喜欢以这种方式打印0%:
fprintf(stderr, "[%-" S(PBWIDTH) ".*s] %u%%", 0, "", 0);
progressbar
中更改fprintf
。 fprintf(stderr, "\r%3u%% [%-" S(PBWIDTH) ".*s]",
percent, percent * PBWIDTH / 100, pbstr);
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 << "\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" , '#');
}
wget
进程? - Alexandre C.