注:根据yigemaser、JFML、CrazyJavar的建议更新,对三位的帮助表示感谢!
在写UI应用时,通常会在一些事件处理的过程中,尤其当这个处理比较耗时的时候,希望能够及时把一些进度信息显示给用户。这时通常大家都会使用一个文本控件来显示这些进度信息。比如下面的程序中,有一个JTextPane和JButton,在JButton中的action事件中需要进行一些耗时的处理,例子程序中使用了Thread.sleep()使当前线程休眠3秒来模拟耗时的操作。action事件处理分为3步,我们希望及时把当前的进度显示在JTextPane上。
代码如下:
但在实际运行过程中可以发现,点击JButton后,JTextPane并不能及时更新,而是在整个JButton的action事件处理完毕后才能显示出最后的信息。为什么会出现这种情况呢?因为在处理JButton的action事件过程中,虽然更新了JTextPane的内容,但由于JButton的事件处理是在当前main线程中运行,虽然JTextPane更新了内容,但没有得到刷新显示的执行机会。
解决这个问题的方法非常简单,只需要把JButton的action处理代码放入一个新的线程,然后启动这个线程。另外,由于Swing的操作大部分是非线程安全的,所以对Swing界面的刷新也单独放在一个线程,并调用SwingUtilities.invokeLater()执行。这样action事件处理、更新JTextPane的界面和main主线程就分别运行在各自的线程中,都可以及时得到执行。JButton的
showMessage方法如下:
大家可以测试运行观察效果。这样也使界面更加友好,因为如果不把action的处理代码放在一个单独的线程中,用户点击JButton后,界面就停止一切响应,直到action处理代码执行完毕。大家可以扩展这种方法,允许用户随时停止该耗时的操作,使界面更加友好。
在写UI应用时,通常会在一些事件处理的过程中,尤其当这个处理比较耗时的时候,希望能够及时把一些进度信息显示给用户。这时通常大家都会使用一个文本控件来显示这些进度信息。比如下面的程序中,有一个JTextPane和JButton,在JButton中的action事件中需要进行一些耗时的处理,例子程序中使用了Thread.sleep()使当前线程休眠3秒来模拟耗时的操作。action事件处理分为3步,我们希望及时把当前的进度显示在JTextPane上。
代码如下:
- packagebruce.test;
- importjavax.swing.*;
- importjava.awt.Container;
- importjava.awt.BorderLayout;
- importjava.awt.Dimension;
- importjava.awt.event.WindowAdapter;
- importjava.awt.event.ActionListener;
- importjava.awt.event.ActionEvent;
- /**
- *事件处理过程中UI的刷新
- *@authorBruce
- *@version1.0
- */
- publicclassTestUIUpdate2{
- publicTestUIUpdate2(){
- TestUIUpdate2Frameframe=newTestUIUpdate2Frame();
- frame.pack();
- frame.setVisible(true);
- }
- publicstaticvoidmain(String[]args){
- newTestUIUpdate2();
- }
- }
- classTestUIUpdate2FrameextendsJFrame{
- JTextPanepane=newJTextPane();
- JButtonbutton=newJButton("action...");
- TestUIUpdate2Frame(){
- init();
- this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- button.addActionListener(newActionListener(){
- publicvoidactionPerformed(ActionEvente){
- try{
- pane.setText("stepone...");
- Thread.sleep(3000);
- pane.setText("\nsteptwo...");
- Thread.sleep(3000);
- pane.setText("\nfinished.");
- Thread.sleep(3000);
- }
- catch(InterruptedExceptionie){
- //ignored
- }
- }
- });
- }
- privatevoidinit(){
- pane.setPreferredSize(newDimension(300,200));
- Containercontent=getContentPane();
- content.setLayout(newBorderLayout());
- content.add(pane,BorderLayout.CENTER);
- content.add(button,BorderLayout.SOUTH);
- }
- }
但在实际运行过程中可以发现,点击JButton后,JTextPane并不能及时更新,而是在整个JButton的action事件处理完毕后才能显示出最后的信息。为什么会出现这种情况呢?因为在处理JButton的action事件过程中,虽然更新了JTextPane的内容,但由于JButton的事件处理是在当前main线程中运行,虽然JTextPane更新了内容,但没有得到刷新显示的执行机会。
解决这个问题的方法非常简单,只需要把JButton的action处理代码放入一个新的线程,然后启动这个线程。另外,由于Swing的操作大部分是非线程安全的,所以对Swing界面的刷新也单独放在一个线程,并调用SwingUtilities.invokeLater()执行。这样action事件处理、更新JTextPane的界面和main主线程就分别运行在各自的线程中,都可以及时得到执行。JButton的
- actionPerformed(ActionEvente)的处理代码修改如下:
- [code]button.addActionListener(newActionListener(){
- publicvoidactionPerformed(ActionEvente){
- try
- {
- newThread(){
- publicvoidrun(){
- try{
- showMessage("stepone...");
- Thread.sleep(3000);
- showMessage("\nsteptwo...");
- Thread.sleep(3000);
- showMessage("\nfinished.");
- Thread.sleep(3000);
- }
- catch(InterruptedExceptionie){
- //ignored
- }
- }
- }.start();
- }
- catch(Exceptionex)
- {
- ex.printStackTrace();
- }
- }
- });
showMessage方法如下:
大家可以测试运行观察效果。这样也使界面更加友好,因为如果不把action的处理代码放在一个单独的线程中,用户点击JButton后,界面就停止一切响应,直到action处理代码执行完毕。大家可以扩展这种方法,允许用户随时停止该耗时的操作,使界面更加友好。