Swing中长时间运行的事件回调里进行界面刷新的特殊处理

Swing中长时间运行的事件回调里进行界面刷新的特殊处理
注:以下是Swing GUI处理的一个小小技巧,对此无兴趣者请退散。

在Swing中有这样一种状况:即长时间运行的事件回调,当它运行时,其余的GUI是没有响应的。如果这会持续较长的一段时间,它可能会让使用者感到挫折和困惑。下面一段程序就展示了这一现象,其粗体部分的本意是每隔一秒刷新标签中的文字,但是结果是按钮事件响应完毕后,标签上显示最后一段文字:
package  com.heyang;

import  java.awt.BorderLayout;
import  java.awt.Dimension;
import  java.awt.Toolkit;
import  java.awt.event.ActionEvent;
import  java.awt.event.ActionListener;

import  javax.swing.JButton;
import  javax.swing.JFrame;
import  javax.swing.JLabel;

public   class  MyFrame  extends  JFrame{
    
private   static   final   long  serialVersionUID  =   - 5100794608937579830L ;
    
    
private  JLabel msgLbl;
    
private  JButton cmdBtn;
    
    
public  MyFrame(){
        setTitle(
" MyFrame " );
        
        msgLbl
= new  JLabel( " 提示文字 " );
        cmdBtn
= new  JButton( " 刷新文本 " );
        
        
this .setLayout( new  BorderLayout());
        
this .add(msgLbl,BorderLayout.NORTH);
        
this .add(cmdBtn,BorderLayout.CENTER);
        
        
//  设置大小,位置
        setSizeAndCentralizeMe( 300 200 );
        
        
//  点击窗口右上角的关闭按钮关闭窗口,直接退出程序
         this .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        
//  按钮事件注册
        cmdBtn.addActionListener( new  ActionListener() {
            
public   void  actionPerformed(ActionEvent e) {
                runCmd();
            }
        });
        
        setVisible(
true );
    }
    
    
private   void  runCmd(){
        msgLbl.setText(
"温故而知新,可以为师矣。");
        longTimeProcess(
10);
        
        msgLbl.setText(
"由,汝知之乎!知之为知之,不知为不知,是知也。");
        longTimeProcess(
10);
        
        msgLbl.setText(
"见贤思齐焉,见不贤而内自省也");
        longTimeProcess(
10);
        
        msgLbl.setText(
"士不可以不弘毅,任重而道远。");
        longTimeProcess(
10);
        
        msgLbl.setText(
"岁寒,然后知松柏之后凋也。");
        longTimeProcess(
10
);
    }
    
    
/**
     * 模拟一个长时处理,以100毫秒为单位
     * 
     * 说明:
     * 
@param  mSeconds
     * 创建时间:2011-1-9 下午12:02:28
     
*/
    
private   void  longTimeProcess( int  mSeconds){
        
try {
            Thread.sleep(mSeconds
* 100 );
        }
        
catch (Exception e){
            
        }
    }
    
    
private   void  setSizeAndCentralizeMe( int  width,  int  height) {
        Dimension screenSize 
=  Toolkit.getDefaultToolkit().getScreenSize();
        
this .setSize(width, height);
        
this .setLocation(screenSize.width  /   2   -  width  /   2 , screenSize.height
                
/   2   -  height  /   2 );
    }
    
    
public   static   void  main(String[] args){
        
new  MyFrame();
    }
}

要达到预期的效果,Swing建议:让长时间运行的任务在独立的线程中运行会好很多,这样能够让GUI有适当响应。修改后的代码如下:
package  com.heyang;

import  java.awt.BorderLayout;
import  java.awt.Dimension;
import  java.awt.Toolkit;
import  java.awt.event.ActionEvent;
import  java.awt.event.ActionListener;

import  javax.swing.JButton;
import  javax.swing.JFrame;
import  javax.swing.JLabel;

public   class  MyFrame  extends  JFrame{
    
private   static   final   long  serialVersionUID  =   - 5100794608937579830L ;
    
    
private  JLabel msgLbl;
    
private  JButton cmdBtn;
    
    
public  MyFrame(){
        setTitle(
" MyFrame " );
        
        msgLbl
= new  JLabel( " 提示文字 " );
        cmdBtn
= new  JButton( " 刷新文本 " );
        
        
this .setLayout( new  BorderLayout());
        
this .add(msgLbl,BorderLayout.NORTH);
        
this .add(cmdBtn,BorderLayout.CENTER);
        
        
//  设置大小,位置
        setSizeAndCentralizeMe( 300 200 );
        
        
//  点击窗口右上角的关闭按钮关闭窗口,直接退出程序
         this .setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        
//  按钮事件注册
        cmdBtn.addActionListener( new  ActionListener() {
            
public   void  actionPerformed(ActionEvent e) {
                runCmd();
            }
        });
        
        setVisible(
true );
    }
    
    
private   void  runCmd(){
        new Thread(){
            
public void
 run(){
                msgLbl.setText(
" 温故而知新,可以为师矣。 " );
                longTimeProcess(
10 );
                
                msgLbl.setText(
" 由,汝知之乎!知之为知之,不知为不知,是知也。 " );
                longTimeProcess(
10 );
                
                msgLbl.setText(
" 见贤思齐焉,见不贤而内自省也 " );
                longTimeProcess(
10 );
                
                msgLbl.setText(
" 士不可以不弘毅,任重而道远。 " );
                longTimeProcess(
10 );
                
                msgLbl.setText(
" 岁寒,然后知松柏之后凋也。 " );
                longTimeProcess(
10 );
            }
        }.start();

    }
    
    
/**
     * 模拟一个长时处理,以100毫秒为单位
     * 
     * 说明:
     * 
@param  mSeconds
     * 创建时间:2011-1-9 下午12:02:28
     
*/
    
private   void  longTimeProcess( int  mSeconds){
        
try {
            Thread.sleep(mSeconds
* 100 );
        }
        
catch (Exception e){
            
        }
    }
    
    
private   void  setSizeAndCentralizeMe( int  width,  int  height) {
        Dimension screenSize 
=  Toolkit.getDefaultToolkit().getScreenSize();
        
this .setSize(width, height);
        
this .setLocation(screenSize.width  /   2   -  width  /   2 , screenSize.height
                
/   2   -  height  /   2 );
    }
    
    
public   static   void  main(String[] args){
        
new  MyFrame();
    }
}

以上代码达到了预期效果,其中起关键作用的代码就是以上粗体部分,它将长时处理放到了另一个线程中运行。
这种做法不是唯一解决之道,Sun提供的SwingWorker类可以帮你达到目的,只是要繁琐一些。这样的技巧在耗时检查,与服务器交互和复杂图形处理中都能有所应用。

参考书籍:
O'REILLY 《Java 线程》一书。

最后感谢您看到这里。

何杨,2011年1月9日14:20:37


你可能感兴趣的:(Swing中长时间运行的事件回调里进行界面刷新的特殊处理)