12.6 使用JProgressBar、 ProgressMonitor和BoundedRangeModel创建进度条
进度条是图形界面中广泛使用的GUI
组件,当复制一个较大的文件时,操作系统会显示一个进度条,用于标识复制操作完成的比例;当启动Eclipse
等程序时,因为需要加载较多的资源,故而启动速度较慢,程序也会在启动过程中显示一个进度条,用以表示该软件启动完成的比例。
12.6.1 创建JProgressBar进度条
使用JProgressBar
可以非常方便地创建进度条。
使用JProgressBar
创建进度条的步骤
创建JProgressBard对象
创建一个JProgressBar
对象,创建该对象时可以指定三个参数,用于设置进度条的排列方向(竖直和水平)、进度条的最大值和最小值。也可以在创建该对象时不传入任何参数,而是在后面程序中修改这三个属性。
例如,如下代码创建了JProgressBar
对象
1 2
| JProgressBar bar = new JProgressBar(JProgressBar.VERTICAL);
|
设置进度条的普通属性
调用该对象的常用方法设置进度条的普通属性。JProgressBar
除提供设置排列方向、最大值、最小值的setter
和getter
方法之外,还提供了如下三个方法
方法 |
描述 |
void setBorderPainted(boolean b) |
设置该进度条是否使用边框 |
void setIndeterminate(boolean newValue) |
设置该进度条是否是进度不确定的进度条,如果指定一个进度条的进度不确定,将看到一个滑块在进度条中左右移动。 |
void setStringPainted(boolean b) |
设置是否在进度条中显示完成百分比。 |
当然,JProgressBar
也为上面三个属性提供了getter
方法,但这三个getter
方法通常没有太大作用。
当程序中工作进度改变时,调用JProgressBar
对象的setValue()
方法。当进度条的完成进度发生改变时,程序还可以调用进度条对象的如下两个方法。
方法 |
描述 |
double getPercentComplete() |
返回进度条的完成百分比 |
String getString() |
返回进度字符串的当前值 |
程序 简单进度条
下面程序示范了使用进度条的简单例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import java.awt.*; import javax.swing.*;
public class JProgressBarTest { JFrame frame = new JFrame("测试进度条"); JProgressBar bar = new JProgressBar(JProgressBar.VERTICAL); JCheckBox indeterminate = new JCheckBox("不确定进度"); JCheckBox noBorder = new JCheckBox("不绘制边框");
public void init() { Box box = new Box(BoxLayout.Y_AXIS); box.add(indeterminate); box.add(noBorder); frame.setLayout(new FlowLayout()); frame.add(box); frame.add(bar); bar.setMinimum(0); bar.setMaximum(100); bar.setStringPainted(true); noBorder.addActionListener(event -> bar.setBorderPainted(!noBorder.isSelected())); indeterminate.addActionListener(event -> { bar.setIndeterminate(indeterminate.isSelected()); bar.setStringPainted(!indeterminate.isSelected()); }); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); for (int i = 0; i <= 100; i++) { bar.setValue(i); try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } }
public static void main(String[] args) { new JProgressBarTest().init(); } }
|
上面程序中创建了一个垂直进度条,并通过方法来设置进度条的外观形式:
并通过一个循环来不断改变进度条的value
属性,该value
将会自动转换成进度条的完成百分比
运行该程序,将看到如图12.29所示的效果
在上面程序中,在主程序中使用循环来改变进度条的value
属性,即修改进度条的完成百分比,这是没有任何意义的事情。
通常会希望用进度条去检测其他任务的完成情况,而不是在其他任务的执行过程中主动修改进度条的value
属性,因为其他任务可能根本不知道进度条的存在。此时可以使用一个计时器来不断取得目标任务的完成情况,并根据其完成情况来修改进度条的value
属性。
程序 进度条检测完成度
下面程序改写了上面程序,用一个SimulatedTarget
来模拟一个耗时的任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| import java.awt.*; import javax.swing.*;
public class JProgressBarTest2 { JFrame frame = new JFrame("测试进度条"); JProgressBar bar = new JProgressBar(JProgressBar.VERTICAL); JCheckBox indeterminate = new JCheckBox("不确定进度"); JCheckBox noBorder = new JCheckBox("不绘制边框");
public void init() { Box box = new Box(BoxLayout.Y_AXIS); box.add(indeterminate); box.add(noBorder); frame.setLayout(new FlowLayout()); frame.add(box); frame.add(bar); bar.setStringPainted(true); noBorder.addActionListener(event -> bar.setBorderPainted(!noBorder.isSelected())); final SimulatedActivity target = new SimulatedActivity(1000); new Thread(target).start(); bar.setMinimum(0); bar.setMaximum(target.getAmount()); Timer timer = new Timer(300, e -> bar.setValue(target.getCurrent())); timer.start(); indeterminate.addActionListener(event -> { bar.setIndeterminate(indeterminate.isSelected()); bar.setStringPainted(!indeterminate.isSelected()); }); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); }
public static void main(String[] args) { new JProgressBarTest2().init(); } }
class SimulatedActivity implements Runnable { private volatile int current; private int amount;
public SimulatedActivity(int amount) { current = 0; this.amount = amount; }
public int getAmount() { return amount; }
public int getCurrent() { return current; }
public void run() { while (current < amount) { try { Thread.sleep(50); } catch (InterruptedException e) { } current++; } } }
|
上面程序的运行效果与前一个程序的运行效果大致相同,但这个程序中的JProgressBars
就实用多了,它可以检测并显示SimulatedTarget
的完成进度。
SimulatedActivity
类实现了Runnable
接口,这是一个特殊的接口,实现该接口可以实现多线程功能。
BoundedRangeModel
Swing
组件大都将外观显示和内部数据分离,JProgressBar
也不例外,JProgressBar
组件有一个用于保存其状态数据的Model
对象,这个对象由BoundedRangeModel
对象表示,程序调用JProgressBar
对象的setValue
方法时,实际上是设置BoundedRangeModel
对象的value
属性。
程序可以修改BoundedRangeModel
对象的minimum
属性和maximum
属性,当该Model
对象的这两个属性被修改后,它所对应的JProgressBar
对象的这两个属性也会随之修改,因为JProgressBar
对象的所有状态数据都是保存在该Model
对象中的。
程序监听JProgressBar
完成比例的变化,也是通过为BoundedRangeModel
提供监听器来实现的BoundedRangeModel
提供了如下一个方法来添加监听器。
方法 |
描述 |
void addChangeListener(ChangeListener x) |
用于监听JProgressBar 完成比例的变化,每当JProgressBar 的value 属性被改变时,系统都会触发ChangeListener 监听器的stateChanged() 方法。 |
代码 进度条状态变化监听器
下面代码为进度条的状态变化添加了一个监听器
1 2 3 4
| bar.getModel().addChangeListener(ce -> { });
|