如何使用进度条

有时,在程序中运行的任务可能需要一段时间才能完成。一个用户友好的程序向用户提供一些指示,表明任务正在执行,任务可能花费多 Long 时间以及已经完成了多少工作。指示工作或进度的一种方法是使用动画图像。

指示工作的另一种方法是使用Cursor类和Component-定义的setCursor方法设置 await 光标。例如,以下代码使 await 光标在container上方时显示 await 光标(包括其中未指定任何光标的任何组件):

container.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

要传达任务的完成程度,可以使用如下所示的进度条:

典型的进度条

有时您无法立即确定 Long 时间运行的任务的 Long 度,或者该任务可能 Long 时间停留在相同的完成状态。通过将进度栏置于*不确定 Pattern,可以显示没有可衡量的进度的工作。处于不确定 Pattern 的进度条将显示动画,以指示正在进行的工作。进度条可以显示更多有意义的信息后,应立即将其切换回默认的确定 Pattern。在 Java 外观中,不确定的进度条如下所示:

不确定的进度条

Swing 提供了三个类来帮助您使用进度条:

在看到进度条和进度监控器运行后,决定使用进度条还是进度监视器可以帮助您确定哪个适合您的应用程序。

使用确定的进度条

这是一个小型演示应用程序的图片,该应用程序使用进度条来衡量在其自己的线程中运行的任务的进度:

ProgressBarDemo 的快照,它使用进度条

Try this:

以下来自ProgressBarDemo.java的代码创建并设置进度条:

//Where member variables are declared:
JProgressBar progressBar;
...
//Where the GUI is constructed:
progressBar = new JProgressBar(0, task.getLengthOfTask());
progressBar.setValue(0);
progressBar.setStringPainted(true);

创建进度条的构造函数设置进度条的最小值和最大值。您也可以使用setMinimumsetMaximum设置这些值。此程序中使用的最小值和最大值为 0,且该任务的 Long 度是许多程序和任务所特有的。但是,进度条的最小值和最大值可以是任何值,甚至可以是负值。该代码段还将进度条的当前值设置为 0.

setStringPainted的调用使进度条在其范围内显示已完成任务百分比的文本指示。默认情况下,进度条显示其getPercentComplete方法返回的值,格式为百分比,例如 33% 。另外,您可以通过调用setString将默认值替换为其他字符串。例如,

if (/*...half way done...*/)
    progressBar.setString("Half way there!");

当用户单击 开始 时,将创建并执行内部类Task的实例。

public void actionPerformed(ActionEvent evt) {
    startButton.setEnabled(false);
    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    done = false;
    task = new Task();
    task.addPropertyChangeListener(this);
    task.execute();
}

Taskjavax.swing.SwingWorker的子类。 Task实例对ProgressBarDemo做三件重要的事情:

  • 该实例在单独的线程中调用doInBackground。这是 Long 时间运行的任务实际执行的地方。使用后台线程而不是事件分发线程可以防止在任务运行时冻结用户interface。

  • 后台任务完成后,实例将在事件调度线程中调用done方法。

  • 该实例维护一个绑定属性progress,该属性已更新以指示任务的进度。每次progress更改时,都会调用propertyChange方法。

有关SwingWorker的更多信息,请参见Swing 中的并发中的工作线程和 SwingWorker

ProgressBarDemo中的后台任务通过以随机间隔报告随机进度来模拟真实任务。 propertyChange方法通过更新进度条来响应任务progress属性中的更改:

public void propertyChange(PropertyChangeEvent evt) {
    if (!done) {
        int progress = task.getProgress();
        progressBar.setValue(progress);
        taskOutput.append(String.format(
                "Completed %d%% of task.\n", progress));
    }

后台任务完成后,任务的done方法将重置进度栏:

public void done() {
    //Tell progress listener to stop updating progress bar.
    done = true;
    Toolkit.getDefaultToolkit().beep();
    startButton.setEnabled(true);
    setCursor(null); //turn off the wait cursor
    progressBar.setValue(progressBar.getMinimum());
    taskOutput.append("Done!\n");
}

请注意,done方法将done字段设置为true,从而防止propertyChange对进度条进行进一步的更新。这是必需的,因为对progress属性的final更新可能会在调用done之后发生。

使用不确定 Pattern

ProgressBarDemo2中设置为不确定 Pattern,直到实际进度开始:

public void propertyChange(PropertyChangeEvent evt) {
    if (!done) {
        int progress = task.getProgress();
        if (progress == 0) {
            progressBar.setIndeterminate(true);
            taskOutput.append("No progress yet\n");
        } else {
            progressBar.setIndeterminate(false); 
            progressBar.setString(null);
            progressBar.setValue(progress);
            taskOutput.append(String.format(
                    "Completed %d%% of task.\n", progress));
        }
    }
}

代码中的其他更改与字符串 显示有关。显示字符串 的进度条可能比不显示字符串 的高,并且作为演示设计者,我们任意决定此进度条仅在处于默认确定 Pattern 时才显示字符串。但是,我们要避免进度条在更改 Pattern 时更改高度时可能导致的布局丑陋。因此,该代码保留了对setStringPainted(true)的调用,但增加了对setString("")的调用,因此不会显示任何文本。稍后,当进度条从不确定 Pattern 切换到确定 Pattern 时,调用setString(null)会使进度条显示其默认字符串。

我们没有做的一项更改是从progress事件处理程序中删除对progressBar.setValue的调用。该调用不会造成任何危害,因为不确定的进度条不使用其 value 属性,除非将其显示在状态字符串 中。实际上,最好使进度条的数据保持最新,因为某些外观可能不支持不确定 Pattern。

Try this:

  • 单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 ProgressBar2 演示。另外,要自己编译和运行示例,请查阅example index

  • 按“开始”按钮。请注意,只要按下按钮,进度条便会开始制作动画,然后切换回确定 Pattern(例如 ProgressBarDemo)。

如何使用进度监视器

现在,让我们重写 ProgressBarDemo 以使用进度监视器而不是进度条。这是新的演示程序 ProgressMonitorDemo 的图片:

ProgressMonitorDemo 的快照和进度监视器显示的对话框

Try this:

  • 单击启动按钮,使用Java™Web 开始(下载 JDK 7 或更高版本)运行 ProgressMonitor 演示。另外,要自己编译和运行示例,请查阅example index

  • 按“开始”按钮。一定时间后,程序将显示一个进度对话框。

  • 点击“确定”按钮。请注意,即使对话框消失了,任务也会 continue。

  • 启动另一个任务。对话框弹出后,单击“取消”按钮。对话框消失,任务停止。

进度监视器无法再次使用,因此,每次启动新任务时都必须创建一个新监视器。每次用户使用“开始”按钮启动新任务时,该程序都会创建一个进度监视器。

这是创建进度监视器的语句:

progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this,
                                      "Running a Long Task",
                                      "", 0, task.getLengthOfTask());

此代码使用ProgressMonitor的唯一构造函数创建监视器并初始化几个参数:

  • 第一个参数为进度监视器弹出的对话框提供父组件。

  • 第二个参数是一个字符串,它描述了被监视任务的性质。该字符串 显示在对话框中。有关此参数的详细信息,请参见进度监控 API

  • 第三个参数是另一个提供可更改状态 注解 的字符串。该示例使用一个空字符串 表示对话框应为可更改的状态 注解 留出空间,但该 注解 最初是空的。如果为此参数提供null,则对话框中将省略 注解。每次progress属性更改时,该示例都会更新 注解。它同时更新监视器的当前值:

int progress = task.getProgress();
String message = String.format("Completed %d%%.\n", progress);
progressMonitor.setNote(message);
progressMonitor.setProgress(progress);
taskOutput.append(message);
  • 最后两个参数分别为对话框中显示的进度栏提供最小值和最大值。

默认情况下,进度监视器会 await 最少 500 毫秒,然后再决定是否弹出对话框。它还 await 进度超过最小值。如果计算出要完成任务将花费超过 2000 毫秒,则会显示进度对话框。要调整最短 await 时间,请调用setMillisToDecidedToPopup。要调整显示对话框所需的最短进度,请调用setMillisToPopup

由于本示例使用进度监视器这一简单事实,它添加了使用进度条的程序版本中不存在的功能:用户可以通过单击工具栏上的 取消 按钮来取消任务。对话。这是示例中的代码,用于检查用户是否取消了任务或任务是否正常退出:

if (progressMonitor.isCanceled() || task.isDone()) {
    progressMonitor.close();
    Toolkit.getDefaultToolkit().beep();
    if (progressMonitor.isCanceled()) {
        task.cancel(true);
        taskOutput.append("Task canceled.\n");
    } else {
        taskOutput.append("Task completed.\n");
    }
    startButton.setEnabled(true);
}

请注意,进度监视器本身不会取消任务。它提供了 GUI 和 API,以使程序可以轻松执行此操作。

决定使用进度条还是进度监视器

如果出现以下情况,请使用“进度条” *:

  • 您希望对进度条的配置有更多控制。如果您直接使用进度条,则可以将其设置为不确定状态,使其垂直显示,为其提供显示字符串,在其上注册更改侦听器,并为其提供有界范围模型以控制进度条的最小值,最大值和当前值。

  • 该程序需要显示其他组件以及进度条。

  • 您需要多个进度条。对于某些任务,您需要监视多个参数。例如,除了成功安装了多少文件之外,安装程序还可能监视磁盘空间使用情况。

  • 您需要重新使用进度条。进度条可以重复使用;进度监视器不能。一旦进度监视器决定显示一个对话框(或不显示),进度监视器将无法再次显示它。

如果出现以下情况,请使用“进度监视器” *:

  • 您需要一种简单的方法来在dialog中显示进度。

  • 正在运行的任务是次要的,用户可能对任务的进度不感兴趣。进度监视器为用户提供了一种在任务仍在运行时关闭对话框的方法。

  • 您希望取消任务的简便方法。进度监视器为用户提供了一个 GUI 来取消任务。您所要做的就是调用进度监视器的isCanceled方法,以了解用户是否按下了“取消”按钮。

  • 您的任务在运行时会定期显示一条短消息。进度监视器对话框提供setNote方法,以便任务可以提供有关其正在执行的操作的更多信息。例如,安装任务可能会报告每个文件的名称。

  • 该任务可能不会花费很 Long 时间才能完成。您可以确定正在运行的任务在什么时间点花费的时间足以保证让用户知道它。如果任务在您设置的时间范围内完成,进度监视器将不会弹出对话框。

如果您决定使用进度监视器并且您正在监视的任务正在从 Importing 流中读取,请使用ProgressMonitorInputStream类。

进度监控 API

下表列出了使用进度条和进度监视器的常用 API。由于JProgressBarJComponent的子类,因此在JComponent 类中列出了可能在JProgressBar上调用的其他方法。请注意,ProgressMonitorObject的子类,并且不是可视组件。

监视进度的 API 分为以下几类:

创建进度栏

ConstructorPurpose
JProgressBar()

JProgressBar(int, int)
创建水平进度条。无参数构造函数使用最小值和初始值为 0 且最大值为 100 初始化进度条。带有两个整数参数的构造函数指定最小值和最大值。
JProgressBar(int)
JProgressBar(int,int,int)
创建具有指定方向的进度条,可以是JProgressBar.HORIZONTALJProgressBar.VERTICAL。可选的第二和第三个参数指定最小值和最大值。
JProgressBar(BoundedRangeModel)使用指定的范围模型创建水平进度条。

设置或获取进度栏的约束/值

MethodPurpose
void setValue(int)

int getValue()
设置或获取进度栏的当前值。该值受最小值和最大值的约束。
double getPercentComplete()获得进度条的完成百分比。
void setMinimum(int)
int getMinimum()
设置或获取进度条的最小值。
void setMaximum(int)
int getMaximum()
设置或获取进度条的最大值。
void setModel(BoundedRangeModel)
BoundedRangeModel getModel()
设置或获取进度条使用的模型。该模型构建了进度条的约束和值,因此您可以直接使用它代替上面列出的各个 set/get 方法。

控制进度栏的外观

MethodPurpose
void setIndeterminate(boolean)通过指定true,将进度条置于不确定 Pattern。指定false会将进度条重新设置为其默认的确定 Pattern。
void setOrientation(int)

int getOrientation()
设置或获取进度条是垂直还是水平。可接受的值为JProgressBar.VERTICALJProgressBar.HORIZONTAL
void setBorderPainted(boolean)
boolean isBorderPainted()
设置或获取进度条是否带有边框。
void setStringPainted(boolean)
boolean isStringPainted()
设置或获取进度条是否显示百分比字符串。默认情况下,百分比字符串 的值是getPercentComplete返回的值,格式为百分比。您可以使用setString设置要显示的字符串。
void setString(String)
String getString()
设置或获取百分比字符串。

创建进度监视器

方法或构造函数Purpose
ProgressMonitor(组件,对象,字符串,整数,整数)创建一个进度监视器。 Component参数是监视器对话框的父级。 Object参数是要在对话框中的option pane上放置的消息。该对象的值通常是StringString参数是可更改的状态 注解。最后两个int参数分别为对话框中使用的进度条设置最小值和最大值。
ProgressMonitor getProgressMonitor()

(在ProgressMonitorInputStream中)
获得一个进度监视器,该监视器监视来自 Importing 流的读取。

配置进度监视器

MethodPurpose
void setMinimum(int)

int getMinimum()
设置或获取进度监视器的最小值。监视器使用此值在对话框中设置进度条。
void setMaximum(int)
int getMaximum()
设置或获取进度监视器的最大值。监视器使用此值在对话框中设置进度条。
void setProgress(int)更新监视器的进度。
void setNote(String)
String getNote()
设置或获取状态 注解。该 注解 显示在对话框中。要从对话框中省略状态 注解,请将null作为监视器构造函数的第三个参数。
void setMillisToDecideToPopup(int)
int getMillisToDecideToPopup()
设置或获取时间,显示器应在该时间后决定是否弹出对话框。

终止进度监视器

MethodPurpose
void close()关闭进度监视器。这将处理该对话框。
boolean isCanceled()确定用户是否按下了“取消”按钮。

监视进度的示例

以下示例使用JProgressBarProgressMonitor

ExampleWhere DescribedNotes
ProgressBarDemoThis section使用基本进度条显示在单独线程中运行的任务的进度。
ProgressBarDemo2This section使用基本进度条显示在单独线程中运行的任务的进度。
ProgressMonitorDemoThis section上一个示例的修改,该示例使用进度监视器而不是进度栏。

如果您使用 JavaFX 编程,请参见进度条和进度指示器