练习JProgressBar结合Timer使用。
代码如下:
package luojing; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.Timer; import java.util.TimerTask; public class NewClass { static JProgressBar jpb = null; static JButton jb = null; public static void main(String args[]) { JFrame frm = new JFrame(); Container contentPane = frm.getContentPane(); jpb = new JProgressBar(); jpb.setOrientation(JProgressBar.HORIZONTAL); jpb.setMaximum(100); jpb.setMinimum(0); jpb.setValue(0); jpb.setStringPainted(true); jpb.setPreferredSize(new Dimension(400, 50)); contentPane.add(jpb, BorderLayout.CENTER); jb = new JButton("开始"); jb.addActionListener(new Change()); contentPane.add(jb, BorderLayout.SOUTH); frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frm.pack(); frm.setTitle("进度条"); // 窗口居中 frm.setLocation((Toolkit.getDefaultToolkit().getScreenSize().width - frm.getSize() .width) / 2,(Toolkit.getDefaultToolkit().getScreenSize().height - frm.getSize().height) / 2); frm.setVisible(true); } static class Change implements ActionListener { public void actionPerformed(ActionEvent e) { Timer timer = new Timer(); timer.schedule(new mytask(jpb), 100, 100); jb.setEnabled(false); // 下面这种方法达不到预定效果,因为线程sleep()时用户界面也不会响应,只会在actionPerformde()执行结束后才会响应 /* * for (int i = 0; i <= 100; i++) { try { Thread.sleep(100); * * jpb.setValue(i); * * } catch (InterruptedException e1) { e1.printStackTrace(); } * * } */ // 采用新建一个一个线程来执行累加可以达到预定的效果 /* * new Thread(new Runnable() { public void run() { for (int i = 1; i * <=100; i++) { try { Thread.sleep(100); jpb.setValue(i); } catch * (InterruptedException ie) { } } } }).start(); */ } } } class mytask extends TimerTask { JProgressBar jpb = null; int i = 1; public mytask(JProgressBar jp) { this.jpb = jp; } public void run() { this.jpb.setValue(i++); } }
另附(转):
java中进度条不能更新问题的研究
为什么进度条在事件处理过程中不更新,而是在完成后,从0%调到100%?
分两种情况:
1)在AWT事件线程中执行的操作
当 应用程序在事件线程中执行长时间的操作时,会阻塞正常的AWT事件处理,因此阻止了重绘操作的发生。这同常会在下列情况下发生:应用程序响应一个来自用户 界面的请求时,在连接到一个按钮或其他GUI组件的事件处理程序中执行任务,任务的内容可能会需要较长时间,使事件线程挂起,直至远程系统发出答复为止。 当应用程序调用JProgressBar的setValue方法时,进度条可能更新期内部状态并调用repaint,这样做会把一个事件放置到AWT事件 队列中。不幸的是,直至应用程序的事件处理程序完成其处理并把控制权返回到线程的事件处理循环,才能处理该事件。
可以通过调用JComponent的paintImmediately方法来这样做,该方法有两种形式:
public void paintImmediately(int x, int y, int width, int height);
public void paintImmediately(Rectangel rect);
例如:
Dimension d = bar.getSize();
Rectangel rect = new Rectangle(0,0, d.width, d.height);
...
bar.setValue(progressValue);
bar.paintImmediately(rect);
...
2)在另一个线程中执行的操作
如 果在一个单独的线程中执行该操作,当调用进度条的setValue方法,它的更新不会出现任何问题,问题在于,后台线程必须调用JProgressBar 的setValue。而Swing组件只有在事件线程中才能安全的访问。因此,从执行实际工作的线程调用setValue方法是不安全的!解决的方法是使 用SwingUtilites的invokeLater方法,让AWT事件线程稍后进行setValue调用。
例如:
...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
bar.setValue(value);
}
});
...
还有一种可能,不能再线程中改变swing组件,例如,不能从线程调用label.setText,但是可以使用EventQueue类的invokeLater和invokeAndWait方法,以便在事件调度线程中执行该调用程序。