【问题标题】:Command-line Progress bar with occupied indicator带有占用指示器的命令行进度条
【发布时间】:2015-09-02 08:40:42
【问题描述】:

我有一个程序处理一项庞大而冗长的工作。我预先知道任务的大小,所以我显示了一个进度条。 但是个别的子任务可能需要很长时间,所以最后进度条也可以闲置很长时间,看起来就像一个程序停顿了一样。

对于那里的住院用户,我可能会包含一个指示器,它只是不断地旋转一个简单的 ASCII 动画,让他们放心,仍然有一些计算在进行。 我在将它与进度条更新结合起来时遇到了问题 - 如果我使用回车符,它会显示我的进度条应该在哪里,我宁愿在 PB 之前使用它,如下所示:

Busy /
0     25    50    75    100%
|-----|-----|-----|-----|
[*****************  

代码:

public class Test {

    public static void main(String[] args) {

        try {

            int barLength = 100;
            int jobLength = 501;
            double stepSize = (double) barLength / (double) jobLength;

            String message = "Busy";
            RotatingProgressBar progressBar = new RotatingProgressBar(message);
            progressBar.start();

            System.out
                    .println("0                        25                       50                       75                       100%");
            System.out
                    .println("|------------------------|------------------------|------------------------|------------------------|");

            for (int i = 0; i <= jobLength; i++) {

                Thread.sleep(100);

                double progress = (stepSize * i) / barLength;
                updateProgress(progress, barLength);

            }

            progressBar.setShowProgress(false);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }// END: main

    static void updateProgress(double progressPercentage, int barLength) {

        System.out.print("\r[");
        int i = 0;
        for (; i < (int) (progressPercentage * (barLength - 1)); i++) {
            System.out.print("*");
        }

        for (; i < barLength - 1; i++) {
            System.out.print(" ");
        }

        System.out.print("]");
    }// END: updateProgress

    static class RotatingProgressBar extends Thread {

        private final String anim = "|/-\\";
        private boolean showProgress = true;
        private String message;

        public RotatingProgressBar(String message) {
            this.message = message;
        }

        public void run() {

            int i = 0;

            while (showProgress) {

                System.out.print("\r");
                System.out.print(message + anim.charAt(i++ % anim.length()));

                try {

                    Thread.sleep(10);

                } catch (Exception e) {
                    // do nothing
                }// END: try-catch

            }// END: while

        }// END: run

        public void setShowProgress(boolean showProgress) {
            this.showProgress = showProgress;
        }

//      public void setCarriageColumn(int column) {
//          this.column = column;
//      }
    }// END: class

}// END: class

【问题讨论】:

  • " 如果我​​使用回车,它会显示我的进度条应该在哪里,我宁愿在 PB 之前有它。由于一个进度指示器,此时无法将整个代码库移动到本机:)
  • 您需要使用“退格”字符来“擦除”之前打印的字符,Java 并没有很好地处理这个问题
  • @GáborBakos 我认为我没有比这更清楚的了,它确实显示了我的进度条应该去哪里。如果还是不明白,请运行代码 sn -p 重现问题。
  • @MadProgrammer 在 System.out.print("\b\r") 中?试过了,没啥区别。
  • 不知道\r,但\b 听起来不错

标签: java command-line terminal


【解决方案1】:

在@Stefan Lindenberg 和@nafas 的启发下,我想我解决了这个问题。我将两种方法合二为一,忙碌指示器作为进度条的最后一个字符不断旋转,我用进度更新:

class ProgressBar extends Thread {

    private static final String anim = "|/-\\";
    private boolean showProgress;
    double progressPercentage;
    private final int barLength;

    public ProgressBar(int barLength) {
        this.barLength = barLength;
        this.showProgress = true;
        this.progressPercentage = 0;
    }

    public void run() {

        int i = 0;

        while (showProgress) {

            String progress = "\r";
            int column = (int) (progressPercentage * barLength);
            for (int j = 0; j <= column; j++) {
                progress += ("*");
            }

            System.out.print(progress + anim.charAt(i++ % anim.length()));

            try {

                Thread.sleep(10);

            } catch (Exception e) {
                // do nothing
            }// END: try-catch

        }// END: while

    }// END: run

    public void setShowProgress(boolean showProgress) {
        this.showProgress = showProgress;
    }

    public void setProgressPercentage(double progressPercentage) {
        this.progressPercentage = progressPercentage;
    }
}// END: class

然后这样使用:

        for (int i = 0; i <= jobLength; i++) {

            Thread.sleep(100);

            double progress = (stepSize * i) / barLength;
            progressBar.setProgressPercentage(progress);

        }

看起来不错。

【讨论】:

    【解决方案2】:

    您可以使用此方法删除已打印到 System.out 的字符:

     public void deleteChar(int times) {
        for (int i = 0; i < times; i++) {
            System.out.print((char) 8);
        }
    }
    

    但这(和其他变通方法)不适用于所有类型的终端/控制台。这适用于 Windows cmd、powershell 和大多数 Unix 终端,但在 Eclipse 或 Netbeans 中会失败。

    【讨论】:

    • 那是什么方法? System.out.print(3 个参数); ??
    • 抱歉,取自不同的上下文。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多