C语言实现进度条

progressBar.hpp:

#ifndef __PROGRESSBAR_HPP
#define __PROGRESSBAR_HPP

#include <iostream>
#include <stdexcept>
#include <string>

// the following are UBUNTU/LINUX ONLY terminal color codes.
#define RESET "\033[0m"
#define BLACK "\033[30m"              /* Black */
#define RED "\033[31m"                /* Red */
#define GREEN "\033[32m"              /* Green */
#define YELLOW "\033[33m"             /* Yellow */
#define BLUE "\033[34m"               /* Blue */
#define MAGENTA "\033[35m"            /* Magenta */
#define CYAN "\033[36m"               /* Cyan */
#define WHITE "\033[37m"              /* White */
#define BOLDBLACK "\033[1m\033[30m"   /* Bold Black */
#define BOLDRED "\033[1m\033[31m"     /* Bold Red */
#define BOLDGREEN "\033[1m\033[32m"   /* Bold Green */
#define BOLDYELLOW "\033[1m\033[33m"  /* Bold Yellow */
#define BOLDBLUE "\033[1m\033[34m"    /* Bold Blue */
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
#define BOLDCYAN "\033[1m\033[36m"    /* Bold Cyan */
#define BOLDWHITE "\033[1m\033[37m"   /* Bold White */

class progressbar {
   public:
    // default destructor
    ~progressbar() = default;

    // delete everything else
    progressbar(progressbar const&) = delete;
    progressbar& operator=(progressbar const&) = delete;
    progressbar(progressbar&&) = delete;
    progressbar& operator=(progressbar&&) = delete;

    // default constructor, must call set_niter later
    progressbar();
    progressbar(const std::string& type, int n, bool showbar = true);

    // reset bar to use it again
    void reset();
    // set number of loop iterations
    void set_niter(int iter);
    // chose your style
    void set_done_char(const std::string& sym) { done_char = sym; }
    void set_todo_char(const std::string& sym) { todo_char = sym; }
    void set_opening_bracket_char(const std::string& sym) { opening_bracket_char = sym; }
    void set_closing_bracket_char(const std::string& sym) { closing_bracket_char = sym; }
    // to show only the percentage
    void show_bar(bool flag = true) { do_show_bar = flag; }
    // main function
    void update();
    void update(int n);
    // default style
    void setDefaultStyle();

   private:
    std::string m_type;
    int progress;
    int n_cycles;
    int last_perc;
    bool do_show_bar;
    bool update_is_called;

    std::string done_char;
    std::string todo_char;
    std::string opening_bracket_char;
    std::string closing_bracket_char;
};

progressbar::progressbar()
    : progress(0),
      m_type(GREEN),
      n_cycles(0),
      last_perc(0),
      do_show_bar(true),
      update_is_called(false),
      done_char("#"),
      todo_char(" "),
      opening_bracket_char("["),
      closing_bracket_char("]") {}

progressbar::progressbar(const std::string& type, int n, bool showbar)
    : progress(0),
      m_type(type),
      n_cycles(n),
      last_perc(0),
      do_show_bar(showbar),
      update_is_called(false),
      done_char("#"),
      todo_char(" "),
      opening_bracket_char("["),
      closing_bracket_char("]") {}

void progressbar::reset() {
    progress = 0, update_is_called = false;
    last_perc = 0;
    return;
}

void progressbar::set_niter(int niter) {
    if (niter <= 0)
        throw std::invalid_argument("progressbar::set_niter: number of iterations null or negative");
    n_cycles = niter;
    return;
}

void progressbar::update() {
    if (n_cycles == 0)
        throw std::runtime_error("progressbar::update: number of cycles not set");

    if (!update_is_called) {
        if (do_show_bar == true) {
            std::cout << m_type << ":" << opening_bracket_char;
            for (int _ = 0; _ < 50; _++)
                std::cout << todo_char;
            std::cout << closing_bracket_char << " 0%";
        } else
            std::cout << "0%";
    }
    update_is_called = true;

    // compute percentage, if did not change, do nothing and return
    int perc = progress * 100. / (n_cycles - 1);
    if (perc < last_perc)
        return;

    // update percentage each unit
    if (perc == last_perc + 1) {
        // erase the correct  number of characters
        if (perc <= 10)
            std::cout << "\b\b" << perc << '%';
        else if (perc > 10 and perc < 100)
            std::cout << "\b\b\b" << perc << '%';
        else if (perc == 100)
            std::cout << "\b\b\b" << perc << '%';
    }
    if (do_show_bar == true) {
        // update bar every ten units
        if (perc % 2 == 0) {
            // erase closing bracket
            std::cout << std::string(closing_bracket_char.size(), '\b');
            // erase trailing percentage characters
            if (perc < 10)
                std::cout << "\b\b\b";
            else if (perc >= 10 && perc < 100)
                std::cout << "\b\b\b\b";
            else if (perc == 100)
                std::cout << "\b\b\b\b\b";

            // erase 'todo_char'
            for (int j = 0; j < 50 - (perc - 1) / 2; ++j) {
                std::cout << std::string(todo_char.size(), '\b');
            }

            // add one additional 'done_char'
            if (perc == 0)
                std::cout << todo_char;
            else
                std::cout << done_char;

            // refill with 'todo_char'
            for (int j = 0; j < 50 - (perc - 1) / 2 - 1; ++j)
                std::cout << todo_char;

            // readd trailing percentage characters
            std::cout << closing_bracket_char << ' ' << perc << '%';
            if (perc == 100)
                std::cout << std::endl;
        }
    }
    last_perc = perc;
    ++progress;
    std::cout << std::flush;

    return;
}

void progressbar::update(int n) {
    for (int i = 0; i < n; i++) {
        update();
    }
}

void progressbar::setDefaultStyle() {
    set_todo_char(" ");
    set_done_char("*");
    set_opening_bracket_char("[");
    set_closing_bracket_char("]");
}

#endif

 测试代码test.cpp:

#include <unistd.h>

#include "progressbar.hpp"

int main(int argc, char* argv[]) {
    progressbar bar;
    bar.set_niter(60);
    bar.setDefaultStyle();
    for (size_t i = 0; i < 60; i++) {
        // if ((i % 20) == 0) {
        //     bar.reset();
        // }
        bar.update();
        sleep(1);
    }
    return 0;
}

编译:g++ ./test.cpp -o main, 运行./main, 结果输出:

 

还有点小问题是:输出*不连续,暂时未发现问题在哪里,待修改。

<think>好的,我现在需要回答用户关于用C语言实现动态进度条的问题。首先,我得回忆一下之前提供的引用内容,看看有没有相关的代码示例。引用2和引用3都提到了C语言进度条实现,所以这些可能是关键。 用户想要动态的进度条,也就是在终端中实时更新的效果。通常,这需要控制输出,比如使用回车符`\r`来覆盖当前行,而不是换行。这样可以让进度条在同一行不断更新。 引用2中的代码是一个简单的15行示例,它使用`printf`和`\r`来实现动态效果,同时用`fflush(stdout)`确保输出立即显示。引用3的代码更复杂一些,包含进度条的填充字符和百分比显示。这两个例子都可以作为参考。 接下来,我需要把这些示例整理成一个清晰的步骤说明。首先,动态进度条的基本原理是:使用回车符、刷新输出缓冲区、控制输出格式。然后,分步骤解释如何实现,比如初始化进度条字符串,循环更新,处理显示效果等。 还需要考虑如何添加旋转符号或百分比,这样进度条看起来更生动。引用2中的`arr`数组用来显示旋转的符号,引用3则用了不同的填充字符。这些都可以作为示例代码的一部分。 另外,要注意不同平台的可能差异,比如`usleep`在Windows和Linux下的不同。可能需要提到这一点,或者建议使用可移植的函数。 最后,生成相关问题,帮助用户进一步学习,比如性能优化、原理深入或扩展功能。这些问题应该与进度条实现相关,但又不重复已有的内容。 总结一下,回答的结构应该是先介绍原理,再分步骤讲解,然后给出代码示例,最后附上相关问题。确保代码正确,符合C语言标准,并解释关键点,如`\r`和`fflush`的作用。</think>以下是用C语言实现动态进度条的详细方法和代码示例: ### 一、动态进度条实现原理 1. **行内刷新**:使用回车符$\\r$替代换行符$\\n$实现行内刷新[^2] 2. **缓冲刷新**:通过$fflush(stdout)$强制刷新输出缓冲区[^2] 3. **动态效果**:结合进度百分比+旋转符号+进度条图形化显示[^3] ### 二、分步骤实现代码 ```c #include <stdio.h> #include <unistd.h> // 包含usleep函数 int main() { const int TOTAL = 50; // 总进度单位数 char bar[TOTAL + 1] = {0}; // 进度条数组 const char* spin = "|/-\\"; // 旋转符号 for (int i = 0; i <= TOTAL; i++) { bar[i] = '#'; // 填充进度符号 // 输出格式:[进度条] 百分比 旋转符 printf("\r[%-50s] %3d%% %c", bar, i*2, spin[i % 4]); fflush(stdout); // 强制刷新输出缓冲区 usleep(100000); // 微秒级延时(0.1秒) } printf("\nDone!\n"); return 0; } ``` ### 三、关键代码解析 1. `\r`:将光标移动到行首实现覆盖效果[^2] 2. `%-50s`:左对齐50字符宽度保证进度条长度固定 3. `usleep`:控制刷新频率(100000微秒=0.1秒) 4. `spin[i % 4]`:循环显示4种旋转符号实现动画效果[^3] ### 四、增强特性建议 1. 添加颜色控制:使用ANSI转义序列 2. 支持进度回调:封装为函数供任务调用 3. 多线程处理:分离显示逻辑与任务逻辑
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_21239475

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值