Swing中长时间运行的事件回调里进行界面刷新的特殊处理
注:以下是Swing GUI处理的一个小小技巧,对此无兴趣者请退散。
在Swing中有这样一种状况:即长时间运行的事件回调,当它运行时,其余的GUI是没有响应的。如果这会持续较长的一段时间,它可能会让使用者感到挫折和困惑。下面一段程序就展示了这一现象,其粗体部分的本意是每隔一秒刷新标签中的文字,但是结果是按钮事件响应完毕后,标签上显示最后一段文字:
要达到预期的效果,Swing建议:让长时间运行的任务在独立的线程中运行会好很多,这样能够让GUI有适当响应。修改后的代码如下:
以上代码达到了预期效果,其中起关键作用的代码就是以上粗体部分,它将长时处理放到了另一个线程中运行。
这种做法不是唯一解决之道,Sun提供的SwingWorker类可以帮你达到目的,只是要繁琐一些。这样的技巧在耗时检查,与服务器交互和复杂图形处理中都能有所应用。
参考书籍:
O'REILLY 《Java 线程》一书。
最后感谢您看到这里。
何杨,2011年1月9日14:20:37
在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();
}
}
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();
}
}
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