`
feipigzi
  • 浏览: 110277 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

(二)如何使用Progress Bar

阅读更多
英文文档:http://download.oracle.com/javase/tutorial/uiswing/components/progress.html

如何使用Progress Bars

(1)使用确定模式进度条

(2)使用不确定模式进度条

(3)使用进度监视器

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

(5)ProgressMonitorInputStream输入流进度监视器的使用

 

    有时候程序中的任务需要一段时间才能完成。一个好的程序应该向用户提供了一些指示信息:任务正在运行、任务需要多长时间、任务已经完成多少。这种指示工作可以使用进度的估算来描述(进度条),本质上是一种动态地图片。

    另一种方法是使用等待光标(wait cursor),使用Cursor类和setCursor方法。例如,下面代码使得wait cursor显示在container上(这个container可以使任何未指定cursor的组件)

 

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

    你可以像下面这样使用进度条,告知用户任务已经完成了多少



     有时候,你不能立刻确定一个大任务所需的时间,或者仍无会阻塞在某一个状态很长时间。你可以不通过度量进度,而是把progress bar放入不确定模式(indeterminate mode)。不确定模式的进度条会动态指示任务正在完成。随着进度条可以显示更多有意义的信息,你应该把他转变为默认的确定模式。在Java样式中,不确定模式的进度条是这样的:


(深色块滚动)

 

Swing提供了三个类帮助你使用progress bars:

 

 JProgressBar

    一个可视化的组件,图形化显示已经完成总任务的多少。参考“(1)使用确定模式进度条 使用典型的进度条。参考“(2)使用不确定模式进度条”在任务大小确定前滚动进度条

ProgressMonitor

    一个非可视化组件。该类的实例检测任务进度,并且在必要的时候弹出对话框,参考“(3)使用进度监视器”

ProgressMonitorInputStream

    一个关联进度监视器的输入流,监视器从该输入流中读取数据。你可以像其他基本I/O输入流一样使用它。你可以想”(3)使用进度监视器“中描述那样,通过调用getProgressMonitor和配置它获得该流的进度监视器。

 

    接着介绍“(4)决定使用进度条还是进度监视器”

(1)使用确定模式进度条

    使用进度条度量本线程任务进度:




 
     下面是代码来自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);

 

    这个构造器创建了进度条,设置了进度条的最大最小值。你同样可以通过setMinimum和setMaximun来设置这些值。这个例子程序中的进度条最大值和最小是分别是0和任务的长度。不过,进度条的最大最小是可以使任意值,包括附属。这段代码也设置了进度条的当前值为0.

    setStringPainted的调用使得进度条展现为边界、已完成任务百分比文字描述。默认情况下,进度条显示getPercentComplete方法返回的值。可以选择的是,你可以通过调用setString改变默认的字符串(默认:1%,2%……)。例如:

 

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

 

当用户点击开始,一个内部类任务实例就被创建并运行:

 

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

      Task是javax.swing.SwingWorker 的子类。对于这个demo来讲Task实例实现了三件重要的事情:

    1.实例在分离线程中调用doInBackground。这事大任务真正开始执行。使用后台进程代替事件分派进程,防止任务在进行时,用户任务阻塞了。

    2.当后台进程完成后,task实例在事件分派进程中调用done方法。

    3.这个实例保持一个绑定属性,progress,它更新指示任务进度。另外,propertyChange方法在每次progress改变时都会被调用

    (下一篇文章会介绍Worker Threads and SwingWorker (工作者线程和Swing工作者)和Concurrency in Swing (Swing中的并发))

    demo程序中的后台任务,冒充一个真正的任务,她在随机时间间隔之间反馈进度数量。properChange方法通过更新进度条,对任务的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方法设置done字段为true,防止propertyChange对进度条作更新。这是必须的,因为progress属性的最后更新发生在done调用之后,而progress属性的改变会调用propertyChange。

(2)使用不确定模式进度条


 

    在ProgressBarDemo2.java 中,模式设置为不确定,知道真正的进度开始位置:

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));
        }
    }
}

     代码改变部分与关字符串显示相关。一个显示字符串的进度条应该比demo设计者设计的进度条高,我们自个决定,进度条应该仅在默认情况且为确定模式情况下,才显示字符串。然而,我们想要避免因为模式的改变而使得进度条高度改变,使得布局难看,因此,代码使用了setStringPainted(true),同时增加一个setString(“”)的调用,这样,就没有文本被显示了。接着,当进度条从不确定模式转变为确定模式时,调用setString(null)使得进度条显示默认字符串。

    我们没有移除事件处理器中progressBar.setValue的调用。这个调用不会造成危害,因为一个不确定模式不会使用自己的值属性,除非用它在状态字符串中显示。实际上,忧郁某些外观样式不支持不确定模式,所以保持进度条的数据尽可能更新是一种好的措施。

    (3)如何使用进度条监视器

    现在,我们重写ProgressBarDemo.java ,使用一个进度监视器代替进度条。以下是截图:



     一个进度监视器不能重复使用,因此每一次新任务开始时,一定有一个新的进度监视器被创建。demo中,每点击开始按钮,程序都会创建一个进度监视器。

    这句代码创建了进度监视器

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

     这句代码使用ProgressMonitor唯一的构造器创建监视器并初始化几个参数。

  • 第一个参数:进度监视器提供了弹出对话框的父组件
  • 第二个参数:一个描述被监视任务性质的字符串。这个字符串会显示在对话框上。
  • 第三个参数:一个字符串,提供可可改变的状态注解。如果你使用null作为参数,这个注解就会忽略。这个例子在每次progress属性改变时都更新了注解。
int progress = task.getProgress();
String message = String.format("Completed %d%%.\n", progress);
progressMonitor.setNote(message);
progressMonitor.setProgress(progress);
taskOutput.append(message);
  •  最后两个参数:分别提供了对话框中进度条显示的最大和最小值

    默认情况下,一个进度监视器在决定是否弹出对话框前,至少等待一个最小时间,500毫秒。它同样花大于最小时间去等待progress作改变。如果计算出任务将会花费超过2000毫秒才能完成,进度对话框会显示。调用setMillisToDecidedToPopup调整“确定是否弹出进度监视器”之前要等待的时间量。调用setMillisToPopup调整“显示弹出监视器花费的时间量 ”。

    这个例子使用了一个进度监视器,它增加了一个功能。用户可以通过点击对话框上的cannel按钮取消任务。这里有一段代码,查询用户是否取消任务或是任务正常退出:

 

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使程序容易实现这些功能。

(4)确定使用进度条还是进度监视器

    下列情况可能更适合使用进度条:

  • 你想对进度条的配置进行更多的控制。如果你直接利用进度条工作,你可以设置它为不确定模式,或者让它垂直显示,进度条中显示字符串,在进度条上注册监听器,控制进度条的最大最小和当前值
  • 需要伴随进度条显示其他组件
  • 你需要多个进度条。多任务下,你需要监视不止一个因素(之前的因素是progress变量)。例如,一个安装程序可能监视磁盘可用空间,同时监视已经成功安装多少文件。
  • 你需要重复使用进度条。一个进度条可重复使用,进度监视器则不可以。一旦进度监视器决定了显示(或不显示)进度监视器,这个进度监视器只为当前工作,不能在被其他所使用。

 

    下列情况可能更适合使用进度监视器:

  • 如果你想简单的在对话框中显示进度
  • 所运行的任务是不重要的,用户可能不关心他具体进度。进度监视器提供了一个方法,让用户屏蔽对话框,即便任务还在运行。
  • 你想要容易地取消任务。进度监视器提供了GUI让用户取消任务。你要做的只是调用监督监视器的isCanceled方法,确定用户是否摁下取消按钮。
  • 你的任务在运行期间需要周期性显示一些简短信息。进度监视器对话框提供了setNote方法,这样你的任务就可以提供更多信息。例如,一个安装任务可能会反馈每个安装文件的名字。
  • 任务耗时不长。你确定用户有足够长的时间了解运行任务的目标和效果。如果任务在一个可设置的时间内完成,进度监视器将不会弹出(默认2秒)。

    如果你决定使用进度监视器,并且你所监视的任务是从一个输入流中读取数据,你可以使用ProgressMonitorInputStream类

(5)ProgressMonitorInputStream输入流进度监视器的使用

 

public class ProgressMonitorInputStreamDemo {
	public static void main(String[] args) {
		int len = 0;
		String filePath = "C:\\Documents and Settings\\Administrator\\桌面\\http小记.txt";
		byte[] b = new byte[30];
		JTextArea text = new JTextArea(20,20);
		JFrame  f = new JFrame();
		f.setSize(330,300);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.add(text,BorderLayout.CENTER);
		f.setVisible(true);
		try{
			FileInputStream input = new FileInputStream(filePath);
			ProgressMonitorInputStream in =
				new ProgressMonitorInputStream(f,"读取某某某文件",input);
			while( (len=in.read(b)) != -1){
				String s = new String(b,0,len);
				text.append(s);
				//delay 3 seconds to see progress bar clearly since the file is too small
				Thread.sleep(3000);
			}
		}catch(InterruptedException e){}
		catch(IOException e){}
	}
}

 效果:



     由于需要估算该输入流的可读长度,所以对话框弹出稍慢,某些设置可以参考进度监视器的。

  • 大小: 850 Bytes
  • 大小: 299 Bytes
  • 大小: 9.6 KB
  • 大小: 6 KB
  • 大小: 8.8 KB
  • 大小: 17.7 KB
  • 大小: 12.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics