C 中任意长时间执行的进度条 -- CONSOLE
Progress Bar in C for an arbitrary long execution -- CONSOLE
我已经尽最大努力不仅搜索了 Whosebug,还搜索了其他网站,但找不到符合我需要的东西。我要求的是能够显示进度条(例如 Progress: ####.........)。我现在真的不关心百分比。
问题来了。我不能简单地执行 0-100 for 循环,因为我希望执行和跟踪的代码位于运行任意时间的 while 循环中(问题大小取决于用户的输入,因此不是常数)。
我考虑过跟踪 int 变量中的迭代次数,并尝试对 2、50 或 100 取模,但正如我所说,迭代次数取决于用户输入,因此,只有在特定条件下才能管理。没有其他输出,但进度条已完成,所以我做了一个简单的 printf('#'); while 循环内部及其外部的所有漂亮东西。
这也是个人喜好,但如果不包括也不介意,我希望进度条长度为 50 个字符,因此 100% 执行 = 50 个“#”字符。
如有任何帮助,我们将不胜感激。
经过反复试验,我可能找到了解决方案,但想与某人核实一下。
假设这些变量(均为 int 类型):
num_iterations = 0, MAX_PROGRESS = 100, BAR_LENGTH = 50, num_items = N
我在以下位置打印了“#”字符:
if ((iteration / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items) == 0)
并得到我想要的结果:
|<------------- Enumeration Complete ------------->|
|##################################################| COMPLETED
虽然这逐渐建立起来,但它不是形式
|<------------- Enumeration Complete ------------->|
|##################################................|
我可以用 \r 或 \b 做什么?
所以我很好地包装了之前的代码,这就是我最终得到的。
我用了一点oop
的概念,模拟了一个ProgressBar
的class。这是我为 ProgressBar
:
设计代码的方式
struct tagProgressBarData
{
unsigned long nMaxLen;
unsigned long nCurLen;
char FillChr;
char EmptyChr;
char LeftMargin;
char RightMargin;
};
typedef struct tagProgressBarData PBD;
void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty);
void DrawProgressBar(PBD* p);
在跳转到 InitProgressBar()
和 DrawProgressBar()
的定义之前,这是您应该如何使用我所做的。这是一个例子:
int main()
{
PBD data;
/** You can chose other characters and change the length too! */
InitProgressBar(&data, 50, '[', ']', '#', '.');
/** Now we do something which takes some time. */
/** Let's just calculate some random cubes. */
/** The N you talked about. */
unsigned int N;
printf("How many numbers to compute: ");
scanf("%u", &N);
printf("Calculating the cubes of the first %u numbers.\n", N);
DrawProgressBar(&data);
for(unsigned int i = 1; i <= N; i++)
{
unsigned int CubeResult = i*i*i;
unsigned long nProgress = ( ((unsigned long long)i) * data.nMaxLen) / N;
if (nProgress != data.nCurLen)
{
data.nCurLen = nProgress;
DrawProgressBar(&data);
}
}
return 0;
}
现在,打印进度条的函数定义:
void DrawProgressBar(PBD* p)
{
/** Move to the beginning of the line. */
printf("\r");
/** Print the left margin char. */
printf("%c", p->LeftMargin);
/** Make sure that MaxLen >= CurLen */
if (p->nMaxLen < p->nCurLen)
p->nCurLen = p->nMaxLen;
/** Print the progress with the Fill char. */
for(unsigned long i = 0; i < p->nCurLen; i++)
printf("%c", p->FillChr);
/** Complete whats left with the Fill char. */
for(unsigned long i = 0; i < p->nMaxLen - p->nCurLen; i++)
printf("%c", p->EmptyChr);
/** Print the right margin char. */
printf("%c", p->RightMargin);
}
我也用过这个函数让我的main代码更紧凑:
void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty)
{
p->nMaxLen = MaxLen;
p->nCurLen = 0;
p->LeftMargin = Left;
p->RightMargin = Right;
p->FillChr = Fill;
p->EmptyChr = Empty;
}
如果你想在进度条之前但在同一行上有一些文本(类似于 Progress: [######.............]
),你必须将 DrawProgressBar()
中的 printf("\r");
替换为 for
循环,这样你就可以精确地向后移动进度条的长度。
此外,您还需要一些变量(比方说 bDrawn
),它会告诉您进度条是否已至少绘制一次,以便 for 循环不会将光标移到现有文本上进度条左边。
我也做过,不过好像很依赖物品的数量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int MAX_PROGRESS = 100;
int BAR_LENGTH = 0; // Length of Header
int num_items = 30;
void delay(int milliseconds) {
// Storing start time
clock_t start_time = clock();
// looping till required time is not achieved
while (clock() < start_time + milliseconds);
}
void initialiseProgressBar(char left, char right, char fill) {
printf("%c", left);
for (int i = 0; i < BAR_LENGTH; i ++) {
printf("%c", fill);
}
/** Print the right first (end of line) and then again the left (start of line)
* as the \r will be placed over it and rewrite from there resulting in one
* character less
*/
printf("%c\r%c", right, left);
}
void drawProgressBar(char c) {
// Print according to BAR_LENGTH
for (int i = 0; i < 100; i ++) {
double progress = (i / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items);
if (progress == 0) {
printf("%c", c);
delay(25);
}
// Redraw the stdout stream to show progressing bar
fflush(stdout);
}
}
int main(int argc, char* argv[]) {
// Header
char* header = "|<------------- Progress Bar ------------->|\n";
printf("%s", header);
BAR_LENGTH = strlen(header) - 3; // Account for newline and right character characters
initialiseProgressBar('[', ']', '.');
drawProgressBar('#');
// Footer -- TODO Find better way to finish this without hard coding
printf("] COMPLETED\n");
return 0;
}
假设您知道要计算的项目数量(例如,对列表进行排序、计算不同的事物等),这应该会派上用场:)。
我已经尽最大努力不仅搜索了 Whosebug,还搜索了其他网站,但找不到符合我需要的东西。我要求的是能够显示进度条(例如 Progress: ####.........)。我现在真的不关心百分比。
问题来了。我不能简单地执行 0-100 for 循环,因为我希望执行和跟踪的代码位于运行任意时间的 while 循环中(问题大小取决于用户的输入,因此不是常数)。
我考虑过跟踪 int 变量中的迭代次数,并尝试对 2、50 或 100 取模,但正如我所说,迭代次数取决于用户输入,因此,只有在特定条件下才能管理。没有其他输出,但进度条已完成,所以我做了一个简单的 printf('#'); while 循环内部及其外部的所有漂亮东西。
这也是个人喜好,但如果不包括也不介意,我希望进度条长度为 50 个字符,因此 100% 执行 = 50 个“#”字符。
如有任何帮助,我们将不胜感激。
经过反复试验,我可能找到了解决方案,但想与某人核实一下。
假设这些变量(均为 int 类型):
num_iterations = 0, MAX_PROGRESS = 100, BAR_LENGTH = 50, num_items = N
我在以下位置打印了“#”字符:
if ((iteration / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items) == 0)
并得到我想要的结果:
|<------------- Enumeration Complete ------------->|
|##################################################| COMPLETED
虽然这逐渐建立起来,但它不是形式
|<------------- Enumeration Complete ------------->|
|##################################................|
我可以用 \r 或 \b 做什么?
所以我很好地包装了之前的代码,这就是我最终得到的。
我用了一点oop
的概念,模拟了一个ProgressBar
的class。这是我为 ProgressBar
:
struct tagProgressBarData
{
unsigned long nMaxLen;
unsigned long nCurLen;
char FillChr;
char EmptyChr;
char LeftMargin;
char RightMargin;
};
typedef struct tagProgressBarData PBD;
void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty);
void DrawProgressBar(PBD* p);
在跳转到 InitProgressBar()
和 DrawProgressBar()
的定义之前,这是您应该如何使用我所做的。这是一个例子:
int main()
{
PBD data;
/** You can chose other characters and change the length too! */
InitProgressBar(&data, 50, '[', ']', '#', '.');
/** Now we do something which takes some time. */
/** Let's just calculate some random cubes. */
/** The N you talked about. */
unsigned int N;
printf("How many numbers to compute: ");
scanf("%u", &N);
printf("Calculating the cubes of the first %u numbers.\n", N);
DrawProgressBar(&data);
for(unsigned int i = 1; i <= N; i++)
{
unsigned int CubeResult = i*i*i;
unsigned long nProgress = ( ((unsigned long long)i) * data.nMaxLen) / N;
if (nProgress != data.nCurLen)
{
data.nCurLen = nProgress;
DrawProgressBar(&data);
}
}
return 0;
}
现在,打印进度条的函数定义:
void DrawProgressBar(PBD* p)
{
/** Move to the beginning of the line. */
printf("\r");
/** Print the left margin char. */
printf("%c", p->LeftMargin);
/** Make sure that MaxLen >= CurLen */
if (p->nMaxLen < p->nCurLen)
p->nCurLen = p->nMaxLen;
/** Print the progress with the Fill char. */
for(unsigned long i = 0; i < p->nCurLen; i++)
printf("%c", p->FillChr);
/** Complete whats left with the Fill char. */
for(unsigned long i = 0; i < p->nMaxLen - p->nCurLen; i++)
printf("%c", p->EmptyChr);
/** Print the right margin char. */
printf("%c", p->RightMargin);
}
我也用过这个函数让我的main代码更紧凑:
void InitProgressBar(PBD* p, unsigned long MaxLen, char Left, char Right, char Fill, char Empty)
{
p->nMaxLen = MaxLen;
p->nCurLen = 0;
p->LeftMargin = Left;
p->RightMargin = Right;
p->FillChr = Fill;
p->EmptyChr = Empty;
}
如果你想在进度条之前但在同一行上有一些文本(类似于 Progress: [######.............]
),你必须将 DrawProgressBar()
中的 printf("\r");
替换为 for
循环,这样你就可以精确地向后移动进度条的长度。
此外,您还需要一些变量(比方说 bDrawn
),它会告诉您进度条是否已至少绘制一次,以便 for 循环不会将光标移到现有文本上进度条左边。
我也做过,不过好像很依赖物品的数量。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int MAX_PROGRESS = 100;
int BAR_LENGTH = 0; // Length of Header
int num_items = 30;
void delay(int milliseconds) {
// Storing start time
clock_t start_time = clock();
// looping till required time is not achieved
while (clock() < start_time + milliseconds);
}
void initialiseProgressBar(char left, char right, char fill) {
printf("%c", left);
for (int i = 0; i < BAR_LENGTH; i ++) {
printf("%c", fill);
}
/** Print the right first (end of line) and then again the left (start of line)
* as the \r will be placed over it and rewrite from there resulting in one
* character less
*/
printf("%c\r%c", right, left);
}
void drawProgressBar(char c) {
// Print according to BAR_LENGTH
for (int i = 0; i < 100; i ++) {
double progress = (i / BAR_LENGTH) % (MAX_PROGRESS * BAR_LENGTH * num_items);
if (progress == 0) {
printf("%c", c);
delay(25);
}
// Redraw the stdout stream to show progressing bar
fflush(stdout);
}
}
int main(int argc, char* argv[]) {
// Header
char* header = "|<------------- Progress Bar ------------->|\n";
printf("%s", header);
BAR_LENGTH = strlen(header) - 3; // Account for newline and right character characters
initialiseProgressBar('[', ']', '.');
drawProgressBar('#');
// Footer -- TODO Find better way to finish this without hard coding
printf("] COMPLETED\n");
return 0;
}
假设您知道要计算的项目数量(例如,对列表进行排序、计算不同的事物等),这应该会派上用场:)。