鱼C论坛

 找回密码
 立即注册
查看: 1618|回复: 0

[技术交流] 一个用于在控制台中实现进度显示的类

[复制链接]
发表于 2020-9-10 16:06:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
由于在控制台中只能以打印字符的形式来进行输出,很多时候我们在运行比较大的程序时无法知道完成进度,所以写了一个类来实现这一功能。

  1. //DosProgressBar header file
  2. //"DosProgressBar"用于在控制台中实现进度显示
  3. //版本号: 1.0.1
  4. //作者:三点一洲

  5. #pragma once
  6. #include <cstring>
  7. #include <cstdio>
  8. #include <string>
  9. #include <iostream>
  10. #include <windows.h>
  11. #define __ARR_CAPACITY 100
  12. #define _INIT_VALUE 0
  13. #define _MAX_VALUE 1
  14. #define _PERCENT_MULTI 100
  15. #define _BLOCK_NUMBERS 32
  16. #define _DEFAULT_FLUSH_FREQUENCY 65536
  17. #define _FLUSH_FREQUENCY 3
  18. #define _FILL_BLOCK "█"
  19. #define _STANDEARD_OUT_SIZE (_BLOCK_NUMBERS * 2 + 2)
  20. #define _UNUSED_BAR 0
  21. #define _USING_BAR 1
  22. #define _USED_BAR 2

  23. //设置光标位置(x, y)
  24. void gotoxy(short, short);
  25. //设置光标位置(COORD)
  26. void gotoxy(COORD);
  27. //返回当前光标位置
  28. COORD wherexy();
  29. //获取光标的位置y
  30. int wherey();
  31. //获取光标的位置x
  32. int wherex();
  33. //计算合适的刷新频率
  34. int calcFrequency(int);

  35. class DosProgressBar
  36. {
  37.     typedef int bar_status;
  38.     typedef double progress_value;

  39. private:
  40.     progress_value nowValue;
  41.     bar_status status;
  42.     COORD outPos;
  43.     int flushCount;
  44.     int flushFrequency;

  45. public:
  46.     //格式化进度
  47.     inline std::string percentFormate()
  48.     /* 格式化当前进度 */
  49.     {
  50.         char s[__ARR_CAPACITY];
  51.         sprintf(s, "%.2f%%", nowValue * _PERCENT_MULTI);
  52.         //std::cout<<std::string(s)+"\n";
  53.         return std::string(s);
  54.     }
  55.     //设置当前进度
  56.     inline progress_value setNowValue(progress_value pv)
  57.     /* 设置进度值 */
  58.     {
  59.         nowValue = pv;
  60.         return pv;
  61.     }
  62.     //获得当前进度
  63.     inline progress_value getNowValue()
  64.     /* 获得当前进度 */
  65.     {
  66.         return nowValue;
  67.     }

  68. private:
  69.     //int printProgressBar(const char end = '\0');
  70.     /* 按频率打印出进度条 */
  71.     //int printProgressBar(const std::string &, const char end = '\0');
  72.     /* 按频率打印出有后缀进度条 */

  73.     //回退到开始光标
  74.     void backToStartPos();
  75.     //立即打印进度条
  76.     int printProgressBarSoon(const char end = '\0');
  77.     //立即打印有后缀进度条
  78.     int printProgressBarSoon(const std::string &, const char end = '\0');

  79. public:
  80.     //刷新进度条
  81.     void flushProgressBar(progress_value);
  82.     //重置进度条
  83.     void reSetBar();
  84.     //设置合理刷新频率
  85.     void setFrequency(int);

  86. public:
  87.     inline DosProgressBar(void) : nowValue(0), flushCount(0), outPos({0, 0}), status(_UNUSED_BAR), flushFrequency(_DEFAULT_FLUSH_FREQUENCY)
  88.     {
  89.     }
  90.     inline DosProgressBar(progress_value _nowValue) : nowValue(_nowValue), flushCount(0), outPos({0, 0}), status(_UNUSED_BAR), flushFrequency(_DEFAULT_FLUSH_FREQUENCY)
  91.     {
  92.     }
  93.     ~DosProgressBar(void) {}
  94. };
复制代码

  1. //DosProgressBar source file
  2. //"DosProgressBar"用于在控制台中实现进度显示
  3. //版本号: 1.0.1
  4. //作者:三点一洲

  5. #include "DosProgressBar.h"
  6. #include <cmath>

  7. //获取光标的位置x
  8. int wherex()
  9. {
  10.     CONSOLE_SCREEN_BUFFER_INFO pBuffer;
  11.     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &pBuffer);
  12.     return pBuffer.dwCursorPosition.X;
  13. }

  14. //获取光标的位置y
  15. int wherey()
  16. {
  17.     CONSOLE_SCREEN_BUFFER_INFO pBuffer;
  18.     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &pBuffer);
  19.     return pBuffer.dwCursorPosition.Y;
  20. }

  21. //返回当前光标位置
  22. COORD wherexy()
  23. {
  24.     COORD _coord;
  25.     CONSOLE_SCREEN_BUFFER_INFO pBuffer;
  26.     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &pBuffer);
  27.     _coord.X = pBuffer.dwCursorPosition.X;
  28.     _coord.Y = pBuffer.dwCursorPosition.Y;
  29.     return _coord;
  30. }

  31. //设置光标位置(x, y)
  32. void gotoxy(short x, short y)
  33. {
  34.     COORD pos = {x, y};
  35.     HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  36.     SetConsoleCursorPosition(hOut, pos);        
  37. }

  38. //设置光标位置(COORD)
  39. void gotoxy(COORD _coord)
  40. {
  41.     COORD pos = _coord;
  42.     HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  43.     SetConsoleCursorPosition(hOut, pos);      
  44. }

  45. //计算合适的刷新频率
  46. int calcFrequency(int _t)
  47. {
  48.     int t = (int)(_t / _BLOCK_NUMBERS / ((int)(log( _t < exp(2) ? exp(2) : _t ) / 2)) + 1);
  49.     return t;
  50. }

  51. //回退到开始光标
  52. void DosProgressBar::backToStartPos()
  53. {
  54.     gotoxy(outPos);
  55.     return;
  56. }

  57. //立即打印进度条
  58. int DosProgressBar::printProgressBarSoon(const char end)
  59. {
  60.     std::string outs("|");
  61.     int block = (int)(nowValue * _BLOCK_NUMBERS);
  62.     for (int i = 0; i < block; i++)
  63.     {
  64.         outs += _FILL_BLOCK;
  65.     }
  66.     outs += std::string(_STANDEARD_OUT_SIZE - 2 - block * 2, ' ');
  67.     outs += "|";
  68.     outs += "  " + percentFormate();
  69.     if (end != '\0')
  70.         outs += end;
  71.     return printf("%s", outs.c_str());
  72. }

  73. //立即打印有后缀进度条
  74. int DosProgressBar::printProgressBarSoon(const std::string &suffix, const char end)
  75. {
  76.     int n = printProgressBarSoon('\0') + printf("%s", suffix.c_str());
  77.     if (end != '\0')
  78.         return n + printf("%c", end);
  79.     else
  80.         return n;
  81. }

  82. //刷新进度条
  83. void DosProgressBar::flushProgressBar(progress_value pv)
  84. {
  85.     if (status == _UNUSED_BAR)
  86.     {
  87.         //std::cout<<"\n"<<flushFrequency<<std::endl;
  88.         status = _USING_BAR;
  89.         COORD _co = wherexy();
  90.         if (_co.X > 0)
  91.         {
  92.             _co.Y++;
  93.             _co.X = 0;
  94.         }
  95.         outPos = _co;
  96.         gotoxy(outPos);
  97.     }
  98.     else if (status == _USED_BAR)
  99.     {
  100.         std::cerr << "进度条已使用,请重置后继续使用" << std::endl;
  101.         //exception 1
  102.         //exit(0);
  103.     }
  104.     setNowValue(pv);
  105.     ++flushCount;
  106.     int resetFlag = flushCount / flushFrequency;
  107.     flushCount %= flushFrequency;
  108.     if (resetFlag || nowValue == 1.0)
  109.     {
  110.         gotoxy(outPos);
  111.         printProgressBarSoon('\n');
  112.         if (!(nowValue == 1.0))
  113.         {
  114.             gotoxy(outPos);
  115.         }
  116.         else
  117.         {
  118.             status = _USED_BAR;
  119.         }
  120.     }
  121. }

  122. //重置进度条
  123. void DosProgressBar::reSetBar()
  124. {
  125. }

  126. //设置合理刷新频率
  127. void DosProgressBar::setFrequency(int total)
  128. {
  129.     flushFrequency = calcFrequency(total);
  130.     return;
  131. }
复制代码

  1. #include "DosProgressBar.h"
  2. #define N 100000000  //总循环次数
  3. int main()
  4. {
  5.     DosProgressBar dpb(0.0);
  6.     dpb.setFrequency(N);
  7.     for (int i = 0; i <= N ; i++)
  8.     {
  9.         dpb.flushProgressBar(i * 1.0 / N);
  10.     }
  11.     return 0;
  12. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-3 02:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表