swing界面刷新问题

摘要:
在JavaSwing编程中,我们经常需要动态刷新界面,例如动态刷新JLabel、JTextField等中的文本。我相信很多朋友都遇到了本文将要解决的问题。在下图所示的Swing界面中,我们希望JLabel和JTextField中的文本会不断变化,并在单击按钮时实时显示。

在Java Swing编程中,往往会遇到需要动态刷新界面的时候,例如动态刷新JLabel的文本,JTextField里的文本等等。但是往往却没有达到我们预期的效果,我相信很多朋友都遇到过本文将要说的这个问题。

如下图的Swing界面中,我们期望在点击按钮时,Jlabel和JTextField里的文本能不断的变化,并实时地显示出来。

swing界面刷新问题第1张

这个例子中,我们期望点击按钮后,JLabel和JTextField中每隔一秒钟刷新一下文本,顺序的显示以下的几句文本:

复制代码
Button clicked

Start to change text...

接着显示数字1到10

action end
复制代码

很多人都会像下面的代码这样实现这个功能:

1 MainFrame.java
2 
3 packagecom.longyg.test;
4 
5 public class MainFrame extendsjavax.swing.JFrame {
6 
7 publicMainFrame() {
8 initComponents();
9 }
10 
11 @SuppressWarnings("unchecked")
12 //<editor-fold defaultstate="collapsed" desc="Generated Code"> 
13 private voidinitComponents() {
14 
15 jLabel = newjavax.swing.JLabel();
16 labelText = newjavax.swing.JLabel();
17 jTextField = newjavax.swing.JLabel();
18 fieldText = newjavax.swing.JTextField();
19 button = newjavax.swing.JButton();
20 
21 setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
22 
23 jLabel.setText("JLabel:");
24 
25 labelText.setBorder(javax.swing.BorderFactory.createEtchedBorder());
26 
27 jTextField.setText("JTextField: ");
28 
29 button.setText("click");
30 button.addActionListener(newjava.awt.event.ActionListener() {
31 public voidactionPerformed(java.awt.event.ActionEvent evt) {
32 buttonActionPerformed(evt);
33 }
34 });
35 
36 javax.swing.GroupLayout layout = newjavax.swing.GroupLayout(getContentPane());
37 getContentPane().setLayout(layout);
38 layout.setHorizontalGroup(
39 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
40 .addGroup(layout.createSequentialGroup()
41 .addGap(10, 10, 10)
42 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
43 .addComponent(button)
44 .addGroup(layout.createSequentialGroup()
45 .addComponent(jLabel)
46 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
47 .addComponent(labelText, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE))
48 .addGroup(layout.createSequentialGroup()
49 .addComponent(jTextField)
50 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
51 .addComponent(fieldText, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE)))
52 .addContainerGap(17, Short.MAX_VALUE))
53 );
54 layout.setVerticalGroup(
55 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
56 .addGroup(layout.createSequentialGroup()
57 .addGap(20, 20, 20)
58 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
59 .addComponent(jLabel)
60 .addComponent(labelText, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE))
61 .addGap(18, 18, 18)
62 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
63 .addComponent(jTextField)
64 .addComponent(fieldText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
65 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
66 .addComponent(button)
67 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
68 );
69 
70 pack();
71 }//</editor-fold>
72 
73 private voidbuttonActionPerformed(java.awt.event.ActionEvent evt) { 
74 changeText("Button clicked");
75 try{
76 Thread.sleep(1000);
77 } catch(InterruptedException ex) {
78 ex.printStackTrace();
79 }
80 changeText("Start to change text...");
81 try{
82 Thread.sleep(1000);
83 } catch(InterruptedException ex) {
84 ex.printStackTrace();
85 }
86 for (int i = 0; i < 10; i++) {
87 changeText((i+1)+"");
88 try{
89 Thread.sleep(1000);
90 } catch(InterruptedException ex) {
91 ex.printStackTrace();
92 }
93 }
94 changeText("action end");
95 }
96 
97 private voidchangeText(String text) {
98 labelText.setText(text);
99 fieldText.setText(text);
100 }
101 
102 /**
103 * @paramargs the command line arguments
104 */
105 public static voidmain(String args[]) {
106 java.awt.EventQueue.invokeLater(newRunnable() {
107 
108 public voidrun() {
109 new MainFrame().setVisible(true);
110 }
111 });
112 }
113 //Variables declaration - do not modify 
114 privatejavax.swing.JButton button;
115 privatejavax.swing.JTextField fieldText;
116 privatejavax.swing.JLabel jLabel;
117 privatejavax.swing.JLabel jTextField;
118 privatejavax.swing.JLabel labelText;
119 //End of variables declaration 
120 }

可以看到,在buttonActionPerformed方法中,我们多次调用了setText来期望改变JLabel和JTextField中的文本。当我们运行这段代码,你会很遗憾的发现,点击click后,JLabel和JTextField中并没有如我们所期望的不断的更新并显示不同的文本。而是点击按钮后,界面仿佛被卡住一样,等过了一段时间后,显示出最后一句文本“action end”。

为什么会发生这样奇怪的现象呢?

Java Swing中,界面刷新是线程同步的,也就是说同一时间,只有一个线程能执行刷新界面的代码。如果要多次不断地刷新界面,必须在多线程中调用刷新的方法。

本例中,在buttonActionPerformed方法中多次调用了setText方法来试图刷新JLabel和JTextField的文本。buttonActionPerformed方法运行在主线程中,所以每次调用setText都是运行在主线程中,而且是顺序的执行的。在前面几次调用setText后,线程并没有退出,所以界面刷新线程不能获得执行刷新的机会。而当最后一次setText后,线程退出,界面才能执行刷新。所以我们只能看到最后一次setText的值。

因此,要解决这个问题,我们必须把buttonActionPerformed方法中的代码段放到一个单独的线程中执行。这样它就不会使线程阻塞,当每次setText后,界面刷新线程也能得到执行的机会,从而刷新界面。

下面是修改后的代码,只有buttonActionPerformed方法的代码被修改,其他部分的代码与上面的完全一致。

复制代码
private voidbuttonActionPerformed(java.awt.event.ActionEvent evt) {                                       
        new Thread(newRunnable() {
            @Override
            public voidrun() {
                changeText("Button clicked");
                try{
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    ex.printStackTrace();
                }
                changeText("Start to change text...");
                try{
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    ex.printStackTrace();
                }
                for (int i = 0; i < 10; i++) {
                    changeText((i+1)+"");
                    try{
                        Thread.sleep(1000);
                    } catch(InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
                changeText("action end");
            }
        }).start();
    }
复制代码

我们可以看到,新的buttonActionPerformed方法中,仅仅是把整个代码段放在了一个线程中,并启动了线程。

我们在每次setText后,都睡眠了1秒钟,是为了看到界面真的实时的变化了,如果不睡眠,界面刷新会一闪而过,不利于观察。

再次运行代码,会发现,终于得到了我们期望的效果:JLabel和JTextField中的文本动态的变化了!

免责声明:文章转载自《swing界面刷新问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇docker启动busyboxjavascript之数据推送下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

2019-1-29-C#-Task.Run-和-Task.Factory.StartNew-区别

title author date CreateTime categories C# Task.Run 和 Task.Factory.StartNew 区别 lindexi 2019-01-29 16:14:52 +0800 2018-06-16 16:22:49 +0800 C# 有小伙伴问我,为什么不推荐他使用 Task.Factory....

android 在子线程中使用handler更新界面

1. 在子线程中创建一个handler对象,让这个handler对象获取主线程的looper,这样才能把这个handler中的消息发送到ui线程的消息队列中 下面这个界面当点击updateui按钮就会创建一个对象然后调用它的更新图片和文字的方法,这两个设置方法在子线程中执行。 在更新界面的对象的类中创建一个handler对象,在初始化的时候给他赋值为Lo...

web worker 的传值方式以及耗时对比

背景 前一阵子开发的项目 pptx 导入, 由于自己的代码问题,引起了个性能问题,一个 40p 的 pptx 文件,转换成 json 数据,大概要耗时 60s+ ,虽然后面发现是某个使用频率非常高的函数内部,用了 new Function 构造函数 造成的(所以这里顺便提醒一下,如果你很在乎几毫秒的差距的话,建议谨慎使用哈),但是在优化的过程中,一度怀疑是...

《Java2 实用教程(第五版)》学习指导

《Java2 实用教程(第五版)》 第1章Java入门 主要内容:P1 1.1Java的地位:P1 1.2Java的特点:P2 1.3安装JDK:P5 1.4Java程序的开发步骤:P8 1.5简单的Java应用程序:P9 1.6Java反编译:P13 第2章基本数据类型与数组 主要内容:P17 2.1标识符与关键字:...

使用 dumi 打包 React 组件库并生成文档站点

对于前端团队来说,公共组件库是必须的,紧接着就是完善组件库的文档 社区里关于快速生成文档的工具有很多,如 StoryBook、Docz、Gatsby 在调研了几种文档工具之后,最终我选择了 umi 家族的另一个成员:dumi 因为它集成了 docz,以及打包工具father-build,同时支持创建自己的Markdown 组件 当然最重要的是,我的项目是基...

浅谈 linux 多线程编程和 windows 多线程编程的异同

原文:http://software.intel.com/zh-cn/blogs/2011/03/24/linux-windows/ 很早以前就想写写linux下多线程编程和windows下的多线程编程了,但是每当写时又不知道从哪个地方写起,怎样把自己知道的东西都写出来,下面我就谈谈linux多线程及线程同步,并将它和windows的多线程进行比较,看看他...