当柳上原的风吹向天际的时候...

真正的快乐来源于创造

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
注:以下是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(300200);
        
        
// 点击窗口右上角的关闭按钮关闭窗口,直接退出程序
        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(300200);
        
        
// 点击窗口右上角的关闭按钮关闭窗口,直接退出程序
        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


posted on 2011-01-09 14:08 何杨 阅读(1020) 评论(3)  编辑  收藏

Feedback

# re: Swing中长时间运行的事件回调里进行界面刷新的特殊处理 2011-12-02 15:32 iridiumcao
runCmd 方法中的线程更新了GUI组件,不是妥否?

这几天我也被同样的问题困扰。  回复  更多评论
  

# re: Swing中长时间运行的事件回调里进行界面刷新的特殊处理 2011-12-09 15:47 何杨
@iridiumcao

界面没出问题就行。  回复  更多评论
  

# re: Swing中长时间运行的事件回调里进行界面刷新的特殊处理 2012-01-02 20:13 iridiumcao
@何杨
O(∩_∩)O谢谢  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: