zoukankan      html  css  js  c++  java
  • swing界面刷新问题

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

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

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

    复制代码
    Button clicked
    
    Start to change text...
    
    接着显示数字1到10
    
    action end
    复制代码


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

      1 MainFrame.java
      2 
      3 package com.longyg.test;
      4 
      5 public class MainFrame extends javax.swing.JFrame {
      6 
      7 public MainFrame() {
      8 initComponents();
      9 }
     10 
     11 @SuppressWarnings("unchecked")
     12 // <editor-fold defaultstate="collapsed" desc="Generated Code"> 
     13 private void initComponents() {
     14 
     15 jLabel = new javax.swing.JLabel();
     16 labelText = new javax.swing.JLabel();
     17 jTextField = new javax.swing.JLabel();
     18 fieldText = new javax.swing.JTextField();
     19 button = new javax.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(new java.awt.event.ActionListener() {
     31 public void actionPerformed(java.awt.event.ActionEvent evt) {
     32 buttonActionPerformed(evt);
     33 }
     34 });
     35 
     36 javax.swing.GroupLayout layout = new javax.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 void buttonActionPerformed(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 void changeText(String text) {
     98 labelText.setText(text);
     99 fieldText.setText(text);
    100 }
    101 
    102 /**
    103 * @param args the command line arguments
    104 */
    105 public static void main(String args[]) {
    106 java.awt.EventQueue.invokeLater(new Runnable() {
    107 
    108 public void run() {
    109 new MainFrame().setVisible(true);
    110 }
    111 });
    112 }
    113 // Variables declaration - do not modify 
    114 private javax.swing.JButton button;
    115 private javax.swing.JTextField fieldText;
    116 private javax.swing.JLabel jLabel;
    117 private javax.swing.JLabel jTextField;
    118 private javax.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 void buttonActionPerformed(java.awt.event.ActionEvent evt) {                                       
            new Thread(new Runnable() {
                @Override
                public void run() {
                    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中的文本动态的变化了!

  • 相关阅读:
    hdu 4002 Find the maximum
    hdu 2837 坑题。
    hdu 3123
    zoj Treasure Hunt IV
    hdu 2053 Switch Game 水题一枚,鉴定完毕
    poj 1430 Binary Stirling Numbers
    hdu 3037 Saving Beans
    hdu 3944 dp?
    南阳oj 求N!的二进制表示最低位的1的位置(从右向左数)。
    fzu 2171 防守阵地 II
  • 原文地址:https://www.cnblogs.com/xiaoran1129/p/2576111.html
Copyright © 2011-2022 走看看