本教程针对JDK 8编写。本页描述的示例和实践不利用后续版本引入的改进,并且可能使用不再可用的技术。
请查看Java语言变化以了解Java SE 9及其后续版本中更新的语言特性的摘要。
请查看JDK发布说明以获取有关所有JDK版本的新功能、增强功能和已删除或已弃用选项的信息。
有时,程序中运行的任务可能需要一些时间才能完成。用户友好的程序向用户提供一些指示,表明任务正在进行中,任务可能需要多长时间,已经完成了多少工作。一种指示工作和进度的方法是使用动画图像。
另一种指示工作的方法是设置等待光标,使用Cursor类和Component定义的setCursor方法。例如,下面的代码使得当光标在container上方时(包括其中未指定光标的任何组件),等待光标将被显示:
container.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
为了表明任务的完成程度,可以使用进度条,如下所示:
有时,无法立即确定长时间运行任务的长度,或者任务可能会在同一完成状态停留很长时间。可以通过将进度条置于不确定模式来显示工作而没有可测量的进度。不确定模式下的进度条会显示动画以指示工作正在进行中。一旦进度条可以显示更有意义的信息,应将其切换回默认的确定模式。在Java外观中,不确定进度条如下所示:
Swing提供了三个类来帮助您使用进度条:
JProgressBar
ProgressMonitor
ProgressMonitorInputStream
getProgressMonitor调用来获取流的进度监视器,并按照如何使用进度监视器中的说明进行配置。
在你看到进度条和进度监视器实际操作之后,决定使用进度条还是进度监视器可以帮助你确定哪种适用于你的应用程序。
这是一个使用进度条来测量其自己线程中运行的任务进度的小型演示应用程序的图片:
下面的代码来自ProgressBarDemo.java,创建并设置了进度条:
//声明成员变量的位置: JProgressBar progressBar; ... //构建GUI的位置: progressBar = new JProgressBar(0, task.getLengthOfTask()); progressBar.setValue(0); progressBar.setStringPainted(true);
创建进度条的构造函数设置了进度条的最小值和最大值。你也可以使用setMinimum和setMaximum方法设置这些值。此程序中使用的最小值和最大值为0和任务的长度,这是许多程序和任务的典型值。然而,进度条的最小值和最大值可以是任何值,甚至是负数。代码片段还将进度条的当前值设置为0。
调用setStringPainted方法会导致进度条在其边界内显示任务完成的百分比的文本指示。默认情况下,进度条显示其getPercentComplete方法返回的值格式化为百分数,例如33%。你也可以通过调用setString方法将默认值替换为其他字符串。例如:
if (/*...已完成一半...*/)
progressBar.setString("已完成一半!");
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.SwingWorkerTaskProgressBarDemo
doInBackground。这是实际执行的长时间任务。使用后台线程而不是事件分派线程可以防止用户界面在任务运行时冻结。done方法。progress,用于指示任务的进度。每次progress更改时,都会调用propertyChange方法。SwingWorkerSwingWorker中的Worker Threads and SwingWorkerProgressBarDemopropertyChangeprogress
public void propertyChange(PropertyChangeEvent evt) {
if (!done) {
int progress = task.getProgress();
progressBar.setValue(progress);
taskOutput.append(String.format(
"已完成任务的%d%%。\n", progress));
}
done
public void done() {
// 告诉进度监听器停止更新进度条。
done = true;
Toolkit.getDefaultToolkit().beep();
startButton.setEnabled(true);
setCursor(null); // 关闭等待光标
progressBar.setValue(progressBar.getMinimum());
taskOutput.append("完成!\n");
}
donedonetruepropertyChangedoneprogress
在ProgressBarDemo2中,直到实际进度开始前,它被设置为不确定模式:
public void propertyChange(PropertyChangeEvent evt) {
if (!done) {
int progress = task.getProgress();
if (progress == 0) {
progressBar.setIndeterminate(true);
taskOutput.append("尚无进度\n");
} else {
progressBar.setIndeterminate(false);
progressBar.setString(null);
progressBar.setValue(progress);
taskOutput.append(String.format(
"已完成任务的%d%%。\n", progress));
}
}
}
代码中的其他更改与字符串显示相关。一个显示字符串的进度条很可能比不显示字符串的进度条要高,作为演示设计者,我们任意决定这个进度条只有在默认的确定模式下才显示字符串。然而,我们希望在模式改变时避免可能导致布局不美观的问题。因此,代码中保留了调用setStringPainted(true)的部分,但添加了调用setString("")的部分,以便不显示任何文本。稍后,当进度条从不确定模式切换到确定模式时,调用setString(null)会使进度条显示其默认字符串。
我们没有进行的一个更改是从progress事件处理程序中删除progressBar.setValue的调用。这个调用不会造成任何问题,因为一个不确定的进度条不使用其值属性,除了可能在状态字符串中显示它。实际上,保持进度条的数据尽可能更新是一个好的实践,因为某些外观可能不支持不确定模式。
现在让我们重新编写ProgressBarDemo,使用进度监视器而不是进度条。下面是新的演示程序ProgressMonitorDemo的图片:
进度监视器无法再次使用,因此每次开始新任务时都必须创建一个新的监视器。该程序在用户点击“开始”按钮时创建一个新的进度监视器。
下面是创建进度监视器的语句:
progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this,
"运行一个长时间的任务",
"", 0, task.getLengthOfTask());
这段代码使用ProgressMonitor的唯一构造方法创建监视器,并初始化了几个参数:
null,则对话框中不会显示状态说明。示例在每次progress属性变化时更新状态说明。它同时也更新监视器的当前值:
int progress = task.getProgress();
String message = String.format("已完成 %d%%。\n", progress);
progressMonitor.setNote(message);
progressMonitor.setProgress(progress);
taskOutput.append(message);
默认情况下,进度监视器在决定是否弹出对话框之前等待至少500毫秒。它还会等待进度超过最小值。如果计算出任务需要超过2000毫秒才能完成,进度对话框将出现。要调整最小等待时间,请调用setMillisToDecidedToPopup。要调整对话框出现所需的最小进度时间,请调用setMillisToPopup。
由于这个示例使用了进度监视器,因此添加了一个在使用进度条的版本中不存在的功能:用户可以通过在对话框上点击取消按钮来取消任务。以下是示例中检查用户是否取消了任务或任务是否正常退出的代码:
if (progressMonitor.isCanceled() || task.isDone()) {
progressMonitor.close();
Toolkit.getDefaultToolkit().beep();
if (progressMonitor.isCanceled()) {
task.cancel(true);
taskOutput.append("任务已取消。\n");
} else {
taskOutput.append("任务已完成。\n");
}
startButton.setEnabled(true);
}
请注意,进度监视器本身不会取消任务。它提供GUI和API,以便程序可以轻松地这样做。
如果满足以下条件,请使用进度条:
如果满足以下条件,请使用进度监视器:
isCanceled方法,以查看用户是否按下了取消按钮。setNote方法,以便任务可以提供有关正在进行的操作的进一步信息。例如,安装任务可以报告每个文件的名称。如果您决定使用进度监视器,并且要监视的任务正在从输入流中读取数据,请使用ProgressMonitorInputStream类。
以下表格列出了常用的用于使用进度条和进度监视器的 API。因为JProgressBar是JComponent的子类,您可能会调用JProgressBar上的其他方法,这些方法在JComponent 类中列出。请注意,ProgressMonitor是Object的子类,而不是可视组件。
用于监视进度的 API 分为以下几类:
| 构造函数 | 目的 |
|---|---|
| JProgressBar() JProgressBar(int, int) |
创建一个水平进度条。无参数构造函数初始化进度条,最小值和初始值为0,最大值为100。带有两个整数参数的构造函数指定最小值和最大值。 |
| JProgressBar(int) JProgressBar(int, int, int) |
创建具有指定方向的进度条,可以是JProgressBar.HORIZONTAL或JProgressBar.VERTICAL。可选的第二个和第三个参数指定最小值和最大值。 |
| JProgressBar(BoundedRangeModel) | 使用指定的范围模型创建水平进度条。 |
| 方法 | 目的 |
|---|---|
| void setValue(int) int getValue() |
设置或获取进度条的当前值。该值受最小值和最大值的限制。 |
| double getPercentComplete() | 获取进度条的完成百分比。 |
| void setMinimum(int) int getMinimum() |
设置或获取进度条的最小值。 |
| void setMaximum(int) int getMaximum() |
设置或获取进度条的最大值。 |
| void setModel(BoundedRangeModel) BoundedRangeModel getModel() |
设置或获取进度条使用的模型。模型确定进度条的约束和值,因此您可以直接使用它作为使用上面列出的单独的设置/获取方法的替代方法。 |
| 方法 | 目的 |
|---|---|
| void setIndeterminate(boolean) | 通过指定true,将进度条设置为不确定模式。指定false将进度条恢复到默认的确定模式。 |
| void setOrientation(int) int getOrientation() |
设置或获取进度条是垂直还是水平的。可接受的值为JProgressBar.VERTICAL或JProgressBar.HORIZONTAL。 |
| void setBorderPainted(boolean) boolean isBorderPainted() |
设置或获取进度条是否有边框。 |
| void setStringPainted(boolean) boolean isStringPainted() |
设置或获取进度条是否显示百分比字符串。默认情况下,百分比字符串的值是getPercentComplete返回的值格式化为百分比。您可以使用setString来设置要显示的字符串。 |
| void setString(String) String getString() |
设置或获取百分比字符串。 |
| 方法或构造函数 | 目的 |
|---|---|
| ProgressMonitor(Component, Object, String, int, int) | 创建一个进度监视器。参数Component是监视器对话框的父组件。参数Object是对话框中选项面板上的消息。这个对象的值通常是一个String。参数String是一个可变的状态注释。最后两个int参数分别设置对话框中进度条的最小值和最大值。 |
| ProgressMonitor getProgressMonitor() (在 ProgressMonitorInputStream中) |
获取一个监视从输入流中读取的进度监视器。 |
| 方法 | 目的 |
|---|---|
| void setMinimum(int) int getMinimum() |
设置或获取进度监视器的最小值。该值用于设置对话框中的进度条。 |
| void setMaximum(int) int getMaximum() |
设置或获取进度监视器的最大值。该值用于设置对话框中的进度条。 |
| void setProgress(int) | 更新监视器的进度。 |
void setNote(String)String getNote() |
设置或获取状态说明。该说明将显示在对话框上。如果要从对话框中省略状态说明,请将null作为监视器构造函数的第三个参数。 |
void setMillisToDecideToPopup(int)int getMillisToDecideToPopup() |
设置或获取监视器在多长时间后决定是否弹出对话框。 |
| 方法 | 目的 |
|---|---|
void close() |
关闭进度监视器。这将关闭对话框。 |
boolean isCanceled() |
确定用户是否按下了取消按钮。 |
以下示例使用JProgressBar或ProgressMonitor。
| 示例 | 描述位置 | 备注 |
|---|---|---|
ProgressBarDemo |
本节 | 使用基本进度条显示在单独线程中运行的任务的进度。 |
ProgressBarDemo2 |
本节 | 使用基本进度条显示在单独线程中运行的任务的进度。 |
ProgressMonitorDemo |
本节 | 修改前一个示例,使用进度监视器而不是进度条。 |
如果您正在使用JavaFX进行编程,请参阅进度条和进度指示器。