命令行进度条的实现原理和示例

 

原理简述

对于通常的命令行输出,大部分人的印象都是一行一行递增的模式。而进度条需要每次内容更新都在同一行,容易让人觉得很“神奇”。一些问答网站上,如 StackOverflow,就有人问“某某语言如何实现命令行进度条”。

其实命令行进度条与具体编程语言无关,它只是巧用了回车符。(回车符在很多编程语言中是“\r”)即,在更新进度条时并不会另起一行,而是对进度条整行内容进行覆写,而且新的内容以回车符打头,并且末尾没有换行符。(换行符在很多编程语言中是“\n”)

 

Java版实现示例

命令行进度条的实现原理虽然简单,但是具体实现可以变化万千。在具体项目中可以根据需求自行设计。

此示例中,有两个主要的类:

  • ProgressBar:负责更新进度条内容

  • Worker:模拟执行耗时的工作,并触发进度更新

界面示例

 

Worker

Java代码

 

  1. class Worker {  

  2.   private ProgressBar progressBar;  

  3.   private int workload;  

  4.   

  5.   Worker(int workload, ProgressBar progressBar) {  

  6.     this.workload = workload;  

  7.     this.progressBar = progressBar;  

  8.   }  

  9.   

  10.   void start() {  

  11.     System.out.print("Working...");  

  12.   

  13.     int progress = 0;  

  14.     while (progress < workload) {  

  15.       // 用sleep模拟一个耗时的操作  

  16.       try {  

  17.         Thread.sleep(100);  

  18.       } catch (InterruptedException ignore) {  

  19.       }  

  20.   

  21.       // 更新进度:每次进度加1  

  22.       progress++;  

  23.       progressBar.onProgressChanged(progress);  

  24.     }  

  25.   

  26.     System.out.print("Worker finish.");  

  27.   }  

  28. }  

 

ProgressBar

Java代码

 

  1. class ProgressBar {  

  2.   

  3.   private boolean inited = true;  

  4.   private boolean done = false;  

  5.   // 共10个进度分块  

  6.   private int blockCount = 10;  

  7.   // 用等号表示已完成的进度块  

  8.   private char finishedBlockChar = '=';  

  9.   // 用空格表示未完成的进度块  

  10.   private char unfinishedBlockChar = ' ';  

  11.   

  12.   // 最大进度值  

  13.   private int max;  

  14.   

  15.   ProgressBar(int max) {  

  16.     this.max = max;  

  17.   }  

  18.   

  19.   // 更新进度  

  20.   void onProgressChanged(int progress) {  

  21.     // 工作完成后不执行任何进度信息更新  

  22.     if (done) {  

  23.       return;  

  24.     }  

  25.   

  26.     // 初次出输进度时需要另起一行,避免覆盖之前输出的其它内容  

  27.     if (inited) {  

  28.       System.out.print("\n");  

  29.     }  

  30.   

  31.     if (progress >= max) {  

  32.       progress = max;  

  33.       done = true;  

  34.     }  

  35.     System.out.print(createProgressContent(progress));  

  36.   

  37.     inited = false;  

  38.   

  39.     // 工作完成后需换行,以避免后续其它内容出现在进度条所在行  

  40.     if (done) {  

  41.       System.out.print("\n");  

  42.     }  

  43.   }  

  44.   

  45.   private String createProgressContent(int progress) {  

  46.     StringBuilder sb = new StringBuilder("\rProgress: [");  

  47.   

  48.     int finishedBlockCount = progress * blockCount / max;  

  49.     int unfinishedBlockCount = blockCount - finishedBlockCount;  

  50.     for (int i = 0; i < finishedBlockCount; i++) {  

  51.       sb.append(finishedBlockChar);  

  52.     }  

  53.     for (int i = 0; i < unfinishedBlockCount; i++) {  

  54.       sb.append(unfinishedBlockChar);  

  55.     }  

  56.   

  57.     sb.append("] ");  

  58.     sb.append(progress);  

  59.     sb.append("/");  

  60.     sb.append(max);  

  61.   

  62.     return sb.toString();  

  63.   }  

  64. }  

 

使用示例

Java代码

 

  1. public static void main(String[] args) {  

  2.   

  3.   // 限定最大进度值为100  

  4.   int max = 100;  

  5.   

  6.   ProgressBar progressBar = new ProgressBar(max);  

  7.   // 由工作线程主动发起进度条更新  

  8.   Worker worker = new Worker(max, progressBar);  

  9.   worker.start();  

  10. }  

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页