Linux第一个小程序-进度条

1. \r 和 \n

\n 表示换行,\r 表示换到当前行的开始。

举例说明:
  写一个程序,当程序运行到打印字符串时,遇到 \r 就把光标回到最开始,遇到 \n 就换行。执行完 \r \n 之后光标移动到下一行开头处。(注:\r \n\n 效果相同),程序如下:

在这里插入图片描述

2 缓冲区的概念

2.1 示例1

将代码改乘如下形式,printf 中没有 \r \n,保存并退出,图示如下:


在这里插入图片描述
执行 make 生成 myfile 可执行文件,运行 myfile,观察到闪烁 3s 后打印了 Hello World!

问题:
1、源代码中 sleep 是在 printf 后的,程序都是从上到下执行,为什么不是先打印再延迟 3s 出现命令行呢?

答: 在程序中,printf 先被执行,但是由于由 sleep 函数,导致先被打印的 printf 函数没有被刷新,而是被保存在缓冲区内。

2、为什么加了 \n 后数据就显示出来了呢?

答: 因为缓冲区有自己的刷新策略。字符串暂时以行缓冲的方式保存在缓冲区里,行缓冲指遇到了换行符 \n 就把换行符在内的之前的所有内容全部刷新出来。由于最后进程退出,曾经缓冲区里的数据就被刷新出来。

2.2 示例2

看如下程序:
如果只有 \r 表示光标回到改行开始,但是数据并没有被移除,该程序先打印 printf 内容,然后光标回到最开始,printf 里的内容在显示之前都是存放在缓冲区里的,fflush(stdout) 表示清空输出缓冲区里的内容并把缓冲区内容输出。之后执行 sleep 函数延迟 1s 打印提示符,程序如下:

在这里插入图片描述
此时终端上首先显示 Hello World!,图示如下:

在这里插入图片描述
一秒之后 Hello World! 被提示符覆盖。 如果不加 \r 打印 printf 的内容就不会被覆盖,图示如下:

在这里插入图片描述

2.3 示例3

看如下程序:
当程序执行到 \n 时,缓冲区里的内容立刻被刷新出来,然后每隔 1s 执行打印的动作,图示如下:

在这里插入图片描述
输出结果如图所示:

在这里插入图片描述
如果把程序中的 \n 换成 \r,那么在输出的时候就是 9\r8\r 。。。刷新的时候先把 9 刷新出来然后光标回到开始,下次打印就会把 9 替换掉,图示如下:

在这里插入图片描述
此时保存退出运行可执行程序,发现终端最后什么都没有,因为打印的数据都放在缓冲区,没刷新数据就不能进行显示,图示如下:

在这里插入图片描述
需要 fflush(stdout) 进行刷新,图示如下:

在这里插入图片描述
此时再运行就完成了一个基本的倒计时,图示如下:

在这里插入图片描述
注意: 凡是向显示器打印的所有内容都是字符,如 **printf(“%d”,123);**向屏幕中打印的是字符 1、字符 2 和字符 3。如果将上述代码的 i 改为 10,那么再运行就会导致 0 总是显示,后面的数据仅仅覆盖第一个字符,图示如下:

在这里插入图片描述
所以 应该改为 printf(“2d\r”,i);表示预留出两个字符的空间,把没有覆盖掉的 0 也给覆盖掉。

3 实现一个进度条

进度条样式如下:

在这里插入图片描述

3.1 初始代码

首先编写如下代码:

#include "proc.h"    
#include <string.h>    
#include <unistd.h>    
    
#define SIZE 101    
    
void process()    
{    
  //由于未来会包含最多100个‘#’又因为字符串都以’\0为结尾,所以最终'#'满了之后需要预留一个字节的空间来保存'\0',所以字符串长度定为101    
  char bar[SIZE];    
  //向数组不断添加'#',打印的时候以bar的形式不断对缓冲区进行刷新,每新增一个'#',后面跟'\0'    
  //为了避免麻烦,在最开始的时候就把数组全部初始化成'\0'    
  memset(bar,'\0',sizeof(bar));    
  int i = 0;    
  //循环101次    
  while(i <= 100)    
  {
    //由于换行符\n刷新了缓冲区,所以这里直接输出bar里面的内容
    printf("[%s]\n",bar);
    //设置i位置为'#',当i==100时,数组的第101个位置也被置为'#'                                                                                                                             
    bar[i] = '#';
    i++;
    sleep(1);          
  }                    
}    

结果及分析:

运行此段代码可以看到如下结果,当在输入和输出中遇到换行符 \n 时,执行真正的I/O操作。由于 printf 里面有 \n ,行缓冲区遇到 \n 就会输出行缓冲区里面的内容,即字符串 bar,直到最后退出循环程序结束,图示如下:

在这里插入图片描述

3.2 加入缓冲区进行修正

以上并不是我们想得到的进度条,所以还需要对代码进行修正:
1、由于进度条不会出现换行,所以每次打印的时候需要回到当前行的开始,不需要换行,所以将 printf 里面的 \n 替换成 \r

代码如下:

#include "proc.h"    
#include <string.h>    
#include <unistd.h>    
    
#define SIZE 101    
    
void process()    
{    
  //由于未来会包含最多100个‘#’又因为字符串都以’\0为结尾,所以最终'#'满了之后需要预留一个字节的空间来保存'\0',所以字符串长度定为101    
  char bar[SIZE];    
  //向数组不断添加'#',打印的时候以bar的形式不断对缓冲区进行刷新,每新增一个'#',后面跟'\0'    
  //为了避免麻烦,在最开始的时候就把数组全部初始化成'\0'    
  memset(bar,'\0',sizeof(bar));    
  int i = 0;    
  //循环101次    
  while(i <= 100)    
  {
    //将\n替换成\r,让其每次先进行打印,然后回到行首
    printf("[%s]\r",bar);
    //设置i位置为'#',当i==100时,数组的第101个位置也被置为'#'                                                                                                                             
    bar[i] = '#';
    i++;
    sleep(1);          
  }                    
}    

此时再保存退出,重新 make 并执行,发现光标一直在下一行的行首没有动,因为打印的数据被暂存在缓冲区,只有程序结束后或者缓冲区满了才进行打印。针对此情况,需要对代码进行进一步的改进,图示如下:

在这里插入图片描述
2、加入 fflush(stdout) 刷新缓冲区内容,使其每次循环都将缓冲区里的内容进行输出。

代码如下:

#include "proc.h"    
#include <string.h>    
#include <unistd.h>    
    
#define SIZE 101    
    
void process()    
{    
  //由于未来会包含最多100个‘#’又因为字符串都以’\0为结尾,所以最终'#'满了之后需要预留一个字节的空间来保存'\0',所以字符串长度定为101    
  char bar[SIZE];    
  //向数组不断添加'#',打印的时候以bar的形式不断对缓冲区进行刷新,每新增一个'#',后面跟'\0'    
  //为了避免麻烦,在最开始的时候就把数组全部初始化成'\0'    
  memset(bar,'\0',sizeof(bar));    
  int i = 0;    
  //循环101次    
  while(i <= 100)    
  {
    //将\n替换成\r,让其每次先进行打印,然后回到行首
    printf("[%s]\r",bar);
    //刷新缓冲区里面的内容
    fflush(stdout);
    //设置i位置为'#',当i==100时,数组的第101个位置也被置为'#'                                                                                                                             
    bar[i] = '#';
    i++;
    sleep(1);          
  }                    
}    

运行结果如下:

在这里插入图片描述
在这里插入图片描述

3.3 变成左对齐

但是此时该进度条依旧不符合要求,所以还需进一步改进:让右括号固定位置保持不动,填写100s表示在格式控制里预留100个字符。

代码如下:

#include "proc.h"    
#include <string.h>    
#include <unistd.h>    
#define STYLE '#'    
    
#define SIZE 101    
    
void process()    
{    
  //由于未来会包含最多100个‘#’又因为字符串都以’\0为结尾,所以最终'#'满了之后需要预留一个字节的空间来保存'\0',所以字符串长度定为101    
  char bar[SIZE];     
  //向数组不断添加'#',打印的时候以bar的形式不断对缓冲区进行刷新,每新增一个'#',后面跟'\0'    
  //为了避免麻烦,在最开始的时候就把数组全部初始化成'\0'    
  memset(bar,'\0',sizeof(bar));    
  int i = 0;    
  //循环101次    
  while(i <= 100)    
  {    
    //由于换行符\n刷新了缓冲区,所以这里直接输出bar里面的内容    
    //让右括号固定位置保持不动,填写100s表示在格式控制里预留100个字符    
    printf("[%100s]\r",bar);    
    //设置i位置为'#',当i==100时,数组的第101个位置也被置为'#'    
    fflush(stdout);    
    bar[i] = STYLE;    
    i++;    
    usleep(10000);                                                                                                                                                                         
  }                                                                     
}                           

重新编译运行,会发现此时是从最右侧开始的,图示如下:

在这里插入图片描述
而且在执行完之后命令行会覆盖掉一部分,所以针对这两个问题进行改进,图示如下:

在这里插入图片描述
因为C语言中默认为右对齐,所以将 [%100s] 改为 [%-100s],变成左对齐即可,最后添加 **printf(“\n”);**另起一行打印命令行提示符,就不会覆盖掉打印的字符串了。

代码如下:

#include "proc.h"    
#include <string.h>    
#include <unistd.h>    
#define STYLE '#'    
    
#define SIZE 101    
    
void process()    
{    
  //由于未来会包含最多100个‘#’又因为字符串都以’\0为结尾,所以最终'#'满了之后需要预留一个字节的空间来保存'\0',所以字符串长度定为101    
  char bar[SIZE];    
  //向数组不断添加'#',打印的时候以bar的形式不断对缓冲区进行刷新,每新增一个'#',后面跟'\0'    
  //为了避免麻烦,在最开始的时候就把数组全部初始化成'\0'    
  memset(bar,'\0',sizeof(bar));    
  int i = 0;    
  //循环101次    
  while(i <= 100)    
  {    
    //由于换行符\n刷新了缓冲区,所以这里直接输出bar里面的内容    
    //让右括号固定位置保持不动,填写-100s表示在格式控制里预留100个字符,且左对齐    
    printf("[%-100s]\r",bar);    
    //设置i位置为'#',当i==100时,数组的第101个位置也被置为'#'    
    fflush(stdout);    
    bar[i] = STYLE;    
    i++;    
    usleep(10000);    
  }    
    printf("\n");                                                                                                                                                                          
}    

保存退出编译运行,可以看到这时的进度条已经基本符合要求,但是还缺少一些东西,继续修改代码,图示如下:

在这里插入图片描述
在这里插入图片描述

3.4 以百分比的形式显示进度条的进度

printf 函数参数做出一些改进,让其以百分比的形式显示进度条的进度。

代码如下:

 printf("[%-100s][%d%%]\r",bar,i); 

3.5 添加旋转光标

最后再添加旋转光标,进度条就完成了!那么如何添加旋转光标呢?同一个位置依次输入 “ *| / - \ * ” 然后依次循环下去就相当于一个旋转光标。

代码如下:

#include "proc.h"    
#include <string.h>    
#include <unistd.h>    
#define STYLE '#'    
    
#define SIZE 101    
    
void process()    
{    
  const char *label = "|/-\\";                                                                                                                                                             
  //由于未来会包含最多100个‘#’又因为字符串都以’\0为结尾,所以最终'#'满了之后需要预留一个字节的空间来保存'\0',所以字符串长度定为101    
  char bar[SIZE];     
  //向数组不断添加'#',打印的时候以bar的形式不断对缓冲区进行刷新,每新增一个'#',后面跟'\0'    
  //为了避免麻烦,在最开始的时候就把数组全部初始化成'\0'    
  memset(bar,'\0',sizeof(bar));    
  int i = 0;    
  //循环101次    
  while(i <= 100)    
  {    
    //由于换行符\n刷新了缓冲区,所以这里直接输出bar里面的内容    
    //让右括号固定位置保持不动,填写-100s表示在格式控制里预留100个字符,且左对齐    
    printf("[%-100s][%d%%][%c]\r",bar,i,label[i%4]);    
    //设置i位置为'#',当i==100时,数组的第101个位置也被置为'#'    
    fflush(stdout);    
    bar[i] = STYLE;    
    i++;    
    usleep(100000);    
  }    
    printf("\n");    
}    

保存退出编译运行最后得到符合要求的进度条,图示如下:

在这里插入图片描述
在这里插入图片描述

4 创建的文件结构

创建如下几个文件:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
小程序的audio组件可以让开发者方便地实现音频播放的功能。进度条是音频播放界面中经常用到的一种控件。在小程序中使用audio进度条可以让用户更加清晰地了解音频的播放进度,从而更好地掌握音频的播放状态。 实现audio进度条的方法比较简单。在audio组件中,可以使用onTimeUpdate事件来监听音频的播放进度。当音频播放,该事件会不断触发,并携带当前的播放进度信息。开发者可以通过计算当前的播放进度与总长的比值,得出当前进度条的位置,并动态更新进度条的UI。另外,如果需要实现进度条的拖动功能,也可以在进度条组件上设置bindchange事件,来监听用户对进度条的操作,并根据操作更新音频播放进度。 在实现audio进度条,需要注意的一些点包括:首先,由于音频播放进度是不断变化的,因此需要在不断更新进度条UI的同,尽量减少不必要的UI渲染操作,以提高程序的运行效率。其次,在用户暂停或拖动进度条需要及暂停或调整音频的播放进度,以保证播放的准确性。最后,在设计进度条的样式需要注意与整个应用程序的UI风格保持一致,以提高用户的使用体验。 总之,通过使用小程序的audio组件,并结合进度条控件的应用,能够为用户提供一个清晰、直观的音频播放体验,同也有助于开发者更好地掌握和管理音频的播放进度

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值