文档

Java™ 教程
隐藏目录
如何使用进度条
路径:使用Swing创建GUI
教程:使用Swing组件
章节:如何使用各种组件

如何使用进度条

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

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

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

为了表明任务的完成程度,可以使用进度条,如下所示:

一个典型的进度条

有时,无法立即确定长时间运行任务的长度,或者任务可能会在同一完成状态停留很长时间。可以通过将进度条置于不确定模式来显示工作而没有可测量的进度。不确定模式下的进度条会显示动画以指示工作正在进行中。一旦进度条可以显示更有意义的信息,应将其切换回默认的确定模式。在Java外观中,不确定进度条如下所示:

一个不确定的进度条

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

JProgressBar
用于以图形方式显示总任务完成的组件。有关使用典型进度条的信息和示例,请参见使用确定进度条。在使用不确定模式部分,了解如何使用进度条来显示任务范围未知之前的活动。
ProgressMonitor
不是可见组件。而是该类的一个实例监视任务的进度,并在必要时弹出一个对话框。有关详细信息和使用进度监视器的示例,请参见如何使用进度监视器
ProgressMonitorInputStream
附带进度监视器的输入流,用于监视从流中读取的数据。您可以像使用基本I/O中描述的其他输入流一样使用该流的实例。可以使用getProgressMonitor调用来获取流的进度监视器,并按照如何使用进度监视器中的说明进行配置。

在你看到进度条和进度监视器实际操作之后,决定使用进度条还是进度监视器可以帮助你确定哪种适用于你的应用程序。

使用确定进度条

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

ProgressBarDemo的快照,使用进度条

试一试: 

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

//声明成员变量的位置:
JProgressBar progressBar;
...
//构建GUI的位置:
progressBar = new JProgressBar(0, task.getLengthOfTask());
progressBar.setValue(0);
progressBar.setStringPainted(true);

创建进度条的构造函数设置了进度条的最小值和最大值。你也可以使用setMinimumsetMaximum方法设置这些值。此程序中使用的最小值和最大值为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
  1. 该实例在单独的线程中调用doInBackground。这是实际执行的长时间任务。使用后台线程而不是事件分派线程可以防止用户界面在任务运行时冻结。
  2. 当后台任务完成时,该实例在事件分派线程中调用done方法。
  3. 该实例维护一个绑定属性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的调用。这个调用不会造成任何问题,因为一个不确定的进度条不使用其值属性,除了可能在状态字符串中显示它。实际上,保持进度条的数据尽可能更新是一个好的实践,因为某些外观可能不支持不确定模式。


试一试: 
  1. 点击“启动”按钮以使用Java™ Web Start运行ProgressBar2演示(下载JDK 7或更高版本)。或者,要编译和运行示例,请参考示例索引启动ProgressBar2演示示例
  2. 点击开始按钮。注意,进度条在按钮按下后立即开始动画播放,然后切换回确定模式(就像ProgressBarDemo一样)。

如何使用进度监视器

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

ProgressMonitorDemo的快照和由进度监视器弹出的对话框

试一试: 
  1. 点击“启动”按钮,使用Java™ Web Start运行ProgressMonitor Demo(下载JDK 7或更高版本)。或者,如果想要自己编译和运行示例,请参考示例索引启动ProgressMonitor Demo示例
  2. 点击“开始”按钮。在一定的时间后,程序会显示一个进度对话框。
  3. 点击“确定”按钮。注意,尽管对话框已经关闭,任务仍然在继续。
  4. 启动另一个任务。当对话框弹出后,点击“取消”按钮。对话框会消失,任务停止。

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

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

progressMonitor = new ProgressMonitor(ProgressMonitorDemo.this,
                                      "运行一个长时间的任务",
                                      "", 0, task.getLengthOfTask());

这段代码使用ProgressMonitor的唯一构造方法创建监视器,并初始化了几个参数:

默认情况下,进度监视器在决定是否弹出对话框之前等待至少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,以便程序可以轻松地这样做。

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

如果满足以下条件,请使用进度条

如果满足以下条件,请使用进度监视器

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

进度监视 API

以下表格列出了常用的用于使用进度条和进度监视器的 API。因为JProgressBarJComponent的子类,您可能会调用JProgressBar上的其他方法,这些方法在JComponent 类中列出。请注意,ProgressMonitorObject的子类,而不是可视组件。

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

创建进度条
构造函数 目的
JProgressBar()
JProgressBar(int, int)
创建一个水平进度条。无参数构造函数初始化进度条,最小值和初始值为0,最大值为100。带有两个整数参数的构造函数指定最小值和最大值。
JProgressBar(int)
JProgressBar(int, int, int)
创建具有指定方向的进度条,可以是JProgressBar.HORIZONTALJProgressBar.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.VERTICALJProgressBar.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() 确定用户是否按下了取消按钮。

监视进度的示例

以下示例使用JProgressBarProgressMonitor

示例 描述位置 备注
ProgressBarDemo 本节 使用基本进度条显示在单独线程中运行的任务的进度。
ProgressBarDemo2 本节 使用基本进度条显示在单独线程中运行的任务的进度。
ProgressMonitorDemo 本节 修改前一个示例,使用进度监视器而不是进度条。

如果您正在使用JavaFX进行编程,请参阅进度条和进度指示器


上一页: 如何使用密码字段
下一页: 如何使用根窗格