实现控制台上的进度条

来源:互联网 发布:理财软件哪个收益最高 编辑:程序博客网 时间:2024/04/18 20:45

         通常,  控制台程序在执行一个漫长的任务时,需要实时显示当前进度信息, 本文演示了类似GUI进度条控件的实现.

由于需要实时更新进度条信息,并且是要在同一行显示,所以需要用到回车转义字符'\r'.


首先是进度条结构体的定义:

#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <time.h>#include <errno.h>#include <sys/select.h>#include <sys/time.h>#include <sys/types.h>#define bool unsigned char#define true 1#define false 0struct progress_bar_info {    const char *name;    bool interactive;    long init_length;    long step; //步长    long total_length;    int width;    char *buffer;};

接着是几个帮助函数, 主要是获取控制台屏幕大小:

static intget_screen_width(void){    int screen_width = getenv("COLUMNS");    return screen_width;}static intget_screen_height(void){    int screen_height = getenv("LINES");    return screen_height;}

接下来是创建和显示进度条图形的函数:

static voidcreate_image(struct progress_bar_info *pbi, bool done){    char *p = pbi->buffer;    pbi->init_length += pbi->step;    long current_size = pbi->init_length;    int percentage = 0;    int i = 0;    if (current_size >= pbi->total_length) {        percentage = 100;        strcpy(p, "100%");    } else {        percentage = 100.0 * current_size / pbi->total_length;        sprintf (p, "%2d%% ", percentage);    }    p += 4;    int progress_size = 10; //->    *p++ = '[';    int current_progress_size = progress_size * percentage/100;    for (i = 0; i < progress_size; i++) {        if (i < current_progress_size)            *p++ = '>';        else            *p++ = ' ';    }    *p++ = ']';    if (done)        strcpy(p, "   Done!\n");    p = strchr(p, '\0'); //move to the end;}static voiddisplay_image(char *buf){    fprintf(stderr, "\r");//回车, 将光标设置到行的开头    fprintf(stderr, "%s", buf);}

下面是创建进度条函数: 传入参数: 进度条初始长度和总长度

void* progress_bar_create(int initial, int total){    struct progress_bar_info *pbi = (struct progress_bar_info*)malloc(sizeof(struct progress_bar_info));    if (pbi == NULL)        return NULL;    if (initial > total)        total = initial;    pbi->init_length = initial;    pbi->total_length = total;    pbi->step = 2;    pbi->width = get_screen_width() - 1; //dont't use the last screen column    pbi->buffer = (char*)malloc(pbi->width + 100);    create_image(pbi, false);    display_image(pbi->buffer);    return pbi;}

进度条更新:

void progress_bar_update(void *progress_bar){    struct progress_bar_info *pbi = (struct progress_bar_info*)progress_bar;    pbi->init_length += pbi->step;    create_image (pbi, false);    display_image (pbi->buffer);}

进度条完成:

void progress_bar_finish(void *progress_bar){    struct progress_bar_info *pbi = (struct progress_bar_info*)progress_bar;    create_image (pbi, true);    display_image (pbi->buffer);    free(pbi->buffer);}

下面是进度条测试代码:

int mySleep(unsigned int sleepSecond){    struct timeval t_timeval;    t_timeval.tv_sec = sleepSecond;    t_timeval.tv_usec = 0;    select( 0, NULL, NULL, NULL, &t_timeval );    return 0;}void thread_func(void *data){    struct progress_bar_info *pbi = (struct progress_bar_info*)data;    while (pbi->init_length < pbi->total_length) {        progress_bar_update(pbi);        mySleep(1);    }    progress_bar_finish(pbi);#if 0    int i = 0;    for (i = 0; i < 10; i++) {        fprintf(stderr, "%d\r", i);    //    printf(stderr, "\r");        mySleep(1);    }    fprintf(stderr, "\n");#endif}int main(void){    struct progress_bar_info *pbi = progress_bar_create(0, 100);    pthread_t a_thread;    pthread_create(&a_thread, NULL, thread_func, pbi);    pthread_join(a_thread, NULL);    return 0;}