JButton事件处理中UI的刷新问题

注:根据yigemaser、JFML、CrazyJavar的建议更新,对三位的帮助表示感谢!

在写UI应用时,通常会在一些事件处理的过程中,尤其当这个处理比较耗时的时候,希望能够及时把一些进度信息显示给用户。这时通常大家都会使用一个文本控件来显示这些进度信息。比如下面的程序中,有一个JTextPane和JButton,在JButton中的action事件中需要进行一些耗时的处理,例子程序中使用了Thread.sleep()使当前线程休眠3秒来模拟耗时的操作。action事件处理分为3步,我们希望及时把当前的进度显示在JTextPane上。
代码如下:
  1. packagebruce.test;
  2. importjavax.swing.*;
  3. importjava.awt.Container;
  4. importjava.awt.BorderLayout;
  5. importjava.awt.Dimension;
  6. importjava.awt.event.WindowAdapter;
  7. importjava.awt.event.ActionListener;
  8. importjava.awt.event.ActionEvent;
  9. /**
  10. *事件处理过程中UI的刷新
  11. *@authorBruce
  12. *@version1.0
  13. */
  14. publicclassTestUIUpdate2{
  15. publicTestUIUpdate2(){
  16. TestUIUpdate2Frameframe=newTestUIUpdate2Frame();
  17. frame.pack();
  18. frame.setVisible(true);
  19. }
  20. publicstaticvoidmain(String[]args){
  21. newTestUIUpdate2();
  22. }
  23. }
  24. classTestUIUpdate2FrameextendsJFrame{
  25. JTextPanepane=newJTextPane();
  26. JButtonbutton=newJButton("action...");
  27. TestUIUpdate2Frame(){
  28. init();
  29. this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  30. button.addActionListener(newActionListener(){
  31. publicvoidactionPerformed(ActionEvente){
  32. try{
  33. pane.setText("stepone...");
  34. Thread.sleep(3000);
  35. pane.setText("\nsteptwo...");
  36. Thread.sleep(3000);
  37. pane.setText("\nfinished.");
  38. Thread.sleep(3000);
  39. }
  40. catch(InterruptedExceptionie){
  41. //ignored
  42. }
  43. }
  44. });
  45. }
  46. privatevoidinit(){
  47. pane.setPreferredSize(newDimension(300,200));
  48. Containercontent=getContentPane();
  49. content.setLayout(newBorderLayout());
  50. content.add(pane,BorderLayout.CENTER);
  51. content.add(button,BorderLayout.SOUTH);
  52. }
  53. }

但在实际运行过程中可以发现,点击JButton后,JTextPane并不能及时更新,而是在整个JButton的action事件处理完毕后才能显示出最后的信息。为什么会出现这种情况呢?因为在处理JButton的action事件过程中,虽然更新了JTextPane的内容,但由于JButton的事件处理是在当前main线程中运行,虽然JTextPane更新了内容,但没有得到刷新显示的执行机会。

解决这个问题的方法非常简单,只需要把JButton的action处理代码放入一个新的线程,然后启动这个线程。另外,由于Swing的操作大部分是非线程安全的,所以对Swing界面的刷新也单独放在一个线程,并调用SwingUtilities.invokeLater()执行。这样action事件处理、更新JTextPane的界面和main主线程就分别运行在各自的线程中,都可以及时得到执行。JButton的
  1. actionPerformed(ActionEvente)的处理代码修改如下:
  2. [code]button.addActionListener(newActionListener(){
  3. publicvoidactionPerformed(ActionEvente){
  4. try
  5. {
  6. newThread(){
  7. publicvoidrun(){
  8. try{
  9. showMessage("stepone...");
  10. Thread.sleep(3000);
  11. showMessage("\nsteptwo...");
  12. Thread.sleep(3000);
  13. showMessage("\nfinished.");
  14. Thread.sleep(3000);
  15. }
  16. catch(InterruptedExceptionie){
  17. //ignored
  18. }
  19. }
  20. }.start();
  21. }
  22. catch(Exceptionex)
  23. {
  24. ex.printStackTrace();
  25. }
  26. }
  27. });


showMessage方法如下:
  1. privatevoidshowMessage(finalStringmsg){
  2. SwingUtilities.invokeLater(newRunnable(){
  3. publicvoidrun(){
  4. pane.setText(pane.getText()+msg);
  5. }
  6. });
  7. }

大家可以测试运行观察效果。这样也使界面更加友好,因为如果不把action的处理代码放在一个单独的线程中,用户点击JButton后,界面就停止一切响应,直到action处理代码执行完毕。大家可以扩展这种方法,允许用户随时停止该耗时的操作,使界面更加友好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值