实现控制台上的进度条

本文介绍如何在控制台程序中实现类似于GUI的进度条效果,通过使用回车转义字符' '实现在同一行更新进度,并详细说明了进度条结构体的定义及辅助函数,用于获取控制台屏幕大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         通常,  控制台程序在执行一个漫长的任务时,需要实时显示当前进度信息, 本文演示了类似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 0

struct progress_bar_info {
    const char *name;
    bool interactive;
    long init_length;
    long step; //步长
    long total_length;
    int width;
    char *buffer;
};

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

static int
get_screen_width(void)
{
    int screen_width = getenv("COLUMNS");
    return screen_width;
}

static int
get_screen_height(void)
{
    int screen_height = getenv("LINES");
    return screen_height;
}

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

static void
create_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 void
display_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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值