赞
踩
要想实现进度条,我们需要理解两个概念,回车换行与缓冲区。
在C语言中回车换行就是'\n'
但在现实中回车和换行是两码事。
回车:回到最开始的位置。
回车在C语言中是'\r'
换行:从当前位置垂直换到下一行,位置不变。
我们接下来要实现这样的功能:
我们知道每打印一个字符,光标就会往后挪动。我们想每次打印完字符都要回到一开始的位置。这样原来的数据就会被覆盖。新数据就会显示出来。这就是倒计时实现的原理。
缓冲区:C中的缓冲区是行缓冲区,为什么交行缓冲区呢?因为只有当遇到换行’
\n’时,缓冲区的内容才会出来,不然就要等到程序结束后,缓冲区的内容才能出来。
sleep是让程序等上1秒再将结束
结果也正是这样。先打印,然后延迟1秒结束。
那么接下来这样呢?
没有了换行’\n’结果会如何呢?
结果却是等待了约1秒后xiaotao才被打印出来,并且命令行直接在后面接着上去了。
命令行在后面我们是可以理解的,因为没有换行,所以就直接跟在后面了。
但为什么延迟了1秒才打印出来呢?明明C程序中的顺序是先打印后延迟呀。
这其实就是缓冲区的原因,没有换行,打印的内容被放在了缓冲区里出不来。然后又等了一秒钟,程序结束了,缓冲区的内容才被释放出来。
这就说明确实存在缓冲区的,并且满足只有当程序结束后才可以释放。
那我们如果想让缓冲区的内容立即释放该怎么办呢?
fflush(FILE*stream)
C语言会默认帮我们打开三个流:标准输入流,标准输出流,标准错误流。
所以我们只要使用fflush(stdout)就可以将缓冲区的内容释放出来。
不要慢慢悠悠的出来,我要立刻出来
消息是stdout打的,暂存在stdout中,现在要强制刷新
既然回车换行和缓冲区两个概念理解后,我们就可以写倒计时器了。
59 int main()
60 {
66 int cnt =10;
67 while(cnt>=0)
68 {
69 printf("%-2d\r",cnt); //左对齐,要求拥有两个位置
70 fflush(stdout);
71 cnt--;
72
73 sleep(1);
74 }
75 printf("\n");
76 return 0;
77 }
我们想要的进度条是这样的:
.jpg
进度条的两段有两个括号,进度条在里面挪动从0%–100%,进度条是一个箭头形状,后面还有着进度比显示,后面还有着进度运行的状态。并且这个进度条还有颜色。
该小程序是直接用make/makefile自动构建,将processbar.c文件和main.c文件直接编译。
1.首先我们需要定义一个char类型数组,这里就是存放着进度条,而这个进度条形状自己定义。实现进度条的原理其实跟倒计时类似,都是每次新的内容需要覆盖旧的内容,也就是每次输出都需要回车,不同的是,进度条需要每次输出比上次要多输出一个,这样每次覆盖就可以显示往后挪动了。
2.我们定义的数组大小应该为102,因为里面需要存放102个数据,一般我们数据加载是不是都显示从0%~100%,所以我们需要循环101次,然后最后还需要存放’\0’。
3.要注意数组一开始需要初始化。
4.需要预先在[]中间看出100个空间,这样左[就在左边,]右括号就在右边,进度条就往右括号去。
5.然后进度条后面还需要显示进度情况,进度情况其实就是循环的次数,在C语言中两个%%表示%。。
6.我们想要让数组每次都要多出一个数据,那么只要在循环时,先打印出数组内容,再往数组里插入数据。这样就可以实现下一次循环数组的内容覆盖上一次的内容,并且看上去往后挪动了。比如第一次数组里什么都没有,第一次打印空,然后往数据里插入进度符号,第二次循环,符号上次的内容打印出符号,然后又往数组里插入数据,第三次循环,覆盖上次内容再打印出符号,以此类推。
7.我们还需要一个箭头一直往后走,该怎么弄呢?每次先打印完数据后,再往数组里插入符号,每次插入完符号后都需要让插入的位置往后挪动也就是++,所以我们只需要在++后的位置上添加箭头符号即可。
void processbar() 26 int cnt=0; 27 28 char bar[NUM]; 29 //初始化 30 memset(bar,'\0',sizeof(bar)); 31 while(cnt<=100) 32 { 33 printf("[%-100s][%d%%]\r",bar,cnt); //先将内容打印出来 34 fflush(stdout);//将缓冲区内容刷新释放 35 bar[cnt++]=STYLE;//再往该位置插入符号,该位置往后挪动,为了下次插入符号。 36 if(cnt<100)bar[cnt]='>';//可以让++后的位置上放入箭头符号,不过要注意的是cnt只能循坏到100,再++就变成101,那么\0的位置就被覆盖了,所以不能再插入。 37 usleep(50000); 38 } 39 printf("\n"); 40 }
最后我们还可以加上进度状态,就是进度条在挪动,它就会转动。
这该如何实现呢?
原理一样,只需要一个字符数组里存放着 - / | \ 几个符号,然后每次打印都覆盖上一次的内容,就可以出现一个旋转的东西了。
const char* label="-/|\\"; //注意两个\\第一个是转义字符 void processbar() 26 int cnt=0; 27 int len=strlen(label); 28 char bar[NUM]; 29 //初始化 30 memset(bar,'\0',sizeof(bar)); 31 while(cnt<=100) 32 { 33 printf("[%-100s][%d%%][%c]\r",bar,cnt,label[cnt%len]); //先将内容打印出来 34 fflush(stdout);//将缓冲区内容刷新释放 35 bar[cnt++]=STYLE;//再往该位置插入符号,该位置往后挪动,为了下次插入符号。 36 if(cnt<100)bar[cnt]='>';//可以让++后的位置上放入箭头符号,不过要注意的是cnt只能循坏到100,再++就变成101,那么\0的位置就被覆盖了,所以不能再插入。 37 usleep(50000); 38 } 39 printf("\n"); 40 }
进度条可以实现后,我们接下来是模拟使用进度条,进度条怎么使用呢,如何被调用呢?
在不同的场景是不同的,一般循环操作是放在进度条里的,正常的进度条只打印它一个状态时的进度,是由使用它的人来决定从什么地方开始加载进度条。所以循环部分是在进度条的外部被使用者操作的。而进度条程序只需要接收一个比率,然后只打印该比率下的进度条。
//v2版本
9 //是如何调用进度条的,一般不讲循环放在进度条里,进度条只是打印一个比率时的进度
const char* label="-/|\\";
10 char bar[NUM]={0};//直接可以变成全局
11 void processbar(int rate)//只需要一个比率
12 {
13 int len=strlen(label);
14
15 printf("[%-100s][%d%%][%c]\r",bar,rate,label[rate%len]);
16 fflush(stdout);
17 bar[rate++]=STYLE;
18 if(rate<100)bar[rate]='>';
19 }
//v2版本 65 int main() 66 { 67 int total=1000;//比如总容量为1000MB 68 int cur=0;//从一开始下载 69 while(cur<=total) 70 { 71 processbar(cur*100/total);//rate=cur*100/total,表示加载的进度 //调用进度条程序 72 cur+=10;//每次加载的进度,每次更新多少,,, 73 usleep(50000); 74 } 75 printf("\n"); 76 return 0; 77 }
利用函数回调的方法来调用进度条。
void init() 21 { 22 memset(bar,'\0',sizeof(bar)); 23 } //v3:模拟一个安装下载 7 8 typedef void (*call_t)(int);//定义一个函数指针类型 9 //返回值是void,函数参数是int 10 void downloan(call_t cd)//定义一该该类型的变量 11 { 12 int total=1000; 13 int cur=0; 14 while(cur<=total) 15 { 16 int rate=cur*100/total; 17 cd(rate);//将rate串给cd,而cd就是processbar进度条程序,函数回调,调用进度条 18 cur+=10; 19 usleep(50000); 20 } 21 printf("\n"); 22 }
int main() 24 { 25 printf("downloan1\n"); 26 downloan(processbar);//我们就将进度条程序传给cd。 27 init();//当进度满了,那么下一次就无法正常打印出来了,所以当进度条打印完后需要清理一下,进度条,这样下次才可以打印出来。 28 29 printf("downloan2\n"); 30 downloan(processbar); 31 init(); 32 33 printf("downloan3\n"); 34 downloan(processbar); 35 init(); 36 37 printf("downloan4\n"); 38 downloan(processbar); }
最后说一下如何让进度条变成有颜色的,C语言中是可以进行颜色输出的。
printf("以下是测试文字颜色:\n");
printf("\033[30m 黑色\033[m\n");//中间的空格可去
printf("\033[31m 红色\033[m\n");
printf("\033[32m 绿色\033[m\n");
printf("\033[33m 黄色\033[m\n");
printf("\033[34m 蓝色\033[m\n");
printf("\033[35m 紫色\033[m\n");
printf("\033[36m 浅蓝\033[m\n");
printf("\033[37m 白色\033[m\n");
————————————————
printf(LIGHT_BLUE"[%-100s]"NONE"[%d%%][%c]\r",bar,rate,label[rate%len]);
只需将要上色的颜色放在上面两个位置即可。NONE是关闭,必须放在后面。
前面选择自己喜欢的颜色即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。