Merlin 的魔力: 不確定的進(jìn)度條
JProgressBar 的一個(gè)細(xì)微但是重要的更新
級別: 初級
John Zukowski (jaz@zukowski.net), 總裁, JZ Ventures, Inc
2003 年 12 月 01 日
開發(fā)人員用JProgressBar
組件向用戶顯示一項(xiàng)任務(wù)的進(jìn)度。針對非常長的任務(wù)或者難于精確確定完成進(jìn)度的任務(wù),Merlin版本對JProgressBar
增加了一個(gè)不確定模式。本月,專欄作者 John Zukowski 對JProgressBar
的使用作了重新介紹,并討論了它的新的不確定模式。您可以在本文的 討論論壇中與作者以及其他讀者共享您的想法(您也可以單擊文章頂部或者底部的 討論進(jìn)入論壇)。
在 Java 2 SDK, Standard Edition,版本 1.4 中,有了一些大的變化,如增加了像 JSpinner
這樣的新組件、像 SpringLayout
這樣的新布局管理器、或者像 Java Logging API 這樣的新 API。而另一些變化則沒有這么顯著,如小的改進(jìn)或者對現(xiàn)有 API 的優(yōu)化。本月關(guān)于 SpringLayout
組件的技巧就屬于后一種情況。它是細(xì)微的,但是很重要。
JProgressBar
是原來的 Swing 組件集中的一個(gè)。它提供了一種以圖形方式顯示進(jìn)程完成進(jìn)度的簡單方式。當(dāng)進(jìn)程進(jìn)行時(shí),一個(gè)長條就會(huì)在該組件上逐漸延伸,直到任務(wù)完成并且長條全部填滿。長條的移動(dòng)通常是某個(gè)多線程任務(wù)的一部分,這有助于避免阻塞應(yīng)用程序其余部分的進(jìn)度,如常規(guī)的屏幕更新。雖然沒有哪一條特定的規(guī)則說進(jìn)度條必須進(jìn)行線性移動(dòng),但是如果看到進(jìn)程從 10% 移動(dòng)到 35%,然后又回到 27%,然后再增加到 80%,最后以 0% 結(jié)束,作為用戶我會(huì)覺得多少有些古怪。
用五個(gè)構(gòu)造函數(shù)中的一個(gè)來構(gòu)造 JProgressBar
,如清單 1 所示:
清單 1. JProgressBar 構(gòu)造函數(shù)
public JProgressBar() public JProgressBar(int orientation) public JProgressBar(int minimum, int maximum) public JProgressBar(int orientation, int minimum, int maximum) public JProgressBar(BoundedRangeModel model) |
JProgressBar
需要初始化方向和值范圍。方向是通過 JProgressBar
的 VERTICAL
或者 HORIZONTAL
常量確定的。默認(rèn)為 HORIZONTAL
。
在創(chuàng)建了這個(gè)組件并在屏幕上顯示它后,啟動(dòng)第二個(gè)線程以執(zhí)行需要測量其進(jìn)度的任務(wù)。然后定期用 setValue()
方法更新進(jìn)度條的值以顯示任務(wù)的當(dāng)前進(jìn)展。清單 2 顯示了 setValue()
的一個(gè)簡單例子:
清單 2. 簡單的 JProgressBar 使用方法
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.lang.reflect.*; public class ProgressSample { static class BarThread extends Thread { private static int DELAY = 500; JProgressBar progressBar; public BarThread(JProgressBar bar) { progressBar = bar; } public void run() { int minimum = progressBar.getMinimum(); int maximum = progressBar.getMaximum(); Runnable runner = new Runnable() { public void run() { int value = progressBar.getValue(); progressBar.setValue(value+1); } }; for (int i=minimum; i<maximum; i++) { try { SwingUtilities.invokeAndWait(runner); // Our task for each step is to just sleep Thread.sleep(DELAY); } catch (InterruptedException ignoredException) { } catch (InvocationTargetException ignoredException) { } } } } public static void main(String args[]) { // Initialize final JProgressBar aJProgressBar = new JProgressBar(0, 100); final JButton aJButton = new JButton("Start"); ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { aJButton.setEnabled(false); Thread stepper = new BarThread(aJProgressBar); stepper.start(); } }; aJButton.addActionListener(actionListener); JFrame theFrame = new JFrame("Progress Bars"); theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container contentPane = theFrame.getContentPane(); contentPane.add(aJProgressBar, BorderLayout.NORTH); contentPane.add(aJButton, BorderLayout.SOUTH); theFrame.setSize(300, 100); theFrame.show(); } } |
第一次運(yùn)行這段代碼時(shí),您會(huì)看到類似于圖 1 的屏幕。
圖 1. 開始屏幕

單擊這個(gè)按鈕,啟動(dòng)第二個(gè)任務(wù),并在它運(yùn)行時(shí)更新進(jìn)度條。圖 2 顯示了運(yùn)行到一半時(shí)的進(jìn)度條。
圖 2. 屏幕顯示進(jìn)度

這里沒什么特別的。主要代碼創(chuàng)建帶有一個(gè)按鈕和進(jìn)度條的 GUI。當(dāng)您選擇按鈕時(shí),它就引發(fā)操作以更新進(jìn)度條。進(jìn)度條用來對某些任務(wù)進(jìn)行測量。在示例程序中,這個(gè)任務(wù)就是休眠半秒 100 次。
在默認(rèn)情況下,除了進(jìn)度條外,沒有其他關(guān)于進(jìn)度的圖形指示。添加如下的一行代碼,您就可以在任務(wù)完成過程中,讓進(jìn)度條顯示任務(wù)完成的百分比:
aJProgressBar.setStringPainted(true); |
圖 3 顯示了我們增加了新代碼的屏幕:
圖 3. 顯示完成百分比

![]() ![]() |
![]()
|
從 Merlin 版本開始, JProgressBar
還支持另一種模式 ―― 確定。對于非固定步數(shù)的長任務(wù),可以使用這種模式。它顯示固定的動(dòng)畫以表明有些事情正在發(fā)生,但是它不表明完成的百分比。如果您確定了任務(wù)所要花費(fèi)的時(shí)間,就可以切換回確定模式。在不確定模式下, JProgressBar
顯示一個(gè)長條,在顯示區(qū)域中來回移動(dòng)。
清單 3 顯示了這種模式的一個(gè)例子。這個(gè)新方法就是 setIndeterminate()
。值為 true
意味著不確定,而值為 false
則意味著普通或者確定。
清單 3. 不確定進(jìn)度條
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ProgressSample2 { public static void main(String args[]) { final JProgressBar aJProgressBar = new JProgressBar(0, 100); aJProgressBar.setIndeterminate(true); JButton aJButton = new JButton("Toggle"); ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { boolean indeterminate = aJProgressBar.isIndeterminate(); aJProgressBar.setIndeterminate(!indeterminate); } }; aJButton.addActionListener(actionListener); JFrame theFrame = new JFrame("Indeterminate"); theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container contentPane = theFrame.getContentPane(); contentPane.add(aJProgressBar, BorderLayout.NORTH); contentPane.add(aJButton, BorderLayout.SOUTH); theFrame.setSize(300, 100); theFrame.show(); } } |
圖 4顯示相關(guān)的屏幕(您需要想像這個(gè)長條是來回移動(dòng)的)。按鈕用于在進(jìn)度條的不確定和確定模式之間進(jìn)行切換。
圖 4. 不確定模式

有兩種新的 UI 默認(rèn)值用于改變重繪時(shí)間間隔和循環(huán)時(shí)間: ProgressBar.repaintInterval
和 ProgressBar.cycleTime
。改變這些設(shè)置 ―― 如下所示 ―― 會(huì)改變顯示速度。循環(huán)時(shí)間必須是重繪時(shí)間間隔的偶數(shù)倍,所以如果間隔為 100,那么循環(huán)時(shí)間應(yīng)該是 200、500 或者 1000 ―― 但不能是 750。
UIManager.put("ProgressBar.repaintInterval", new Integer(150)); UIManager.put("ProgressBar.cycleTime", new Integer(1050)); |
注意您需要在創(chuàng)建進(jìn)度條 之前設(shè)置這些值。
![]() ![]() |
ProgressBar
還有很多內(nèi)容,但是其他特性在 1.4 版中都沒有改變。我們簡單回顧了這個(gè)組件的原有使用方式,并介紹了在 Merlin 版本中它的新特性。您也可以考慮用 ProgressMonitor
或者 ProgressMonitorInputStream
監(jiān)視這些長任務(wù)的進(jìn)度。它們都在內(nèi)部利用了 JProgressBar
的優(yōu)點(diǎn)。
原文:http://www.ibm.com/developerworks/cn/java/j-mer11183/index.html