JFrame不会实时更新

时间:2016-01-10 02:31:10

标签: java multithreading swing

我的项目包含两部分:逻辑模块和gui界面。 两者都将其引用发送给其他人。

当用户发送消息时,我有一个Key Listener。在这个监听器中,我在逻辑之前调用相同的gui更改,在逻辑之后调用相同的更改 问题是两个更改都会在执行结束时同时显示。

如何实时强制进行GUI更新?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Main {

    // Init DecisionEngine and GUIApplication
    private static final Logic _logic = new Logic();
    private static final GUI _gui = new GUI();

    public static void main(String[] args) {
        // Set DecisionEngine reference in GUIApplication and viceversa
        _gui.setLogicReference(_logic);
        _logic.setGUIRefecence(_gui);

        // User send a message
        _gui.textInput.addKeyListener(new KeyListener(){
            @Override public void keyPressed(KeyEvent e){
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {

                    _gui.somethingChaged1();// CHANGE 1 GUI
                    _logic.thinking();// LOGIC PROCESSING (3sec)
                    _gui.somethingChaged2();// CHANGE 2 GUI

                    e.consume();// Stopping adding an Enter after message
                }
            }
            @Override public void keyTyped(KeyEvent e) {}
            @Override public void keyReleased(KeyEvent e) {}
        });
    }

    private static class Logic {
        GUI gui_ref;

        public Logic() {}
        private void setGUIRefecence(GUI _gui) {gui_ref = _gui;}
        private void thinking() {
            try {Thread.sleep(3000);} catch (InterruptedException ex) {}
        }
    }

    private static class GUI {

        Logic logic_ref;
        private JFrame frame;
        public  JTextArea textInput;
        private JLabel isTyping;

        public GUI() {

            frame = new JFrame();
            textInput = new javax.swing.JTextArea(5, 20);
            isTyping = new JLabel("Normal mode");

            frame.setSize(new Dimension(200,300));
            frame.add(textInput, BorderLayout.PAGE_START);
            frame.add(isTyping, BorderLayout.CENTER);
            frame.revalidate();
            frame.repaint();
            frame.setVisible(true);
        }

        private void setLogicReference(Logic _logic) {logic_ref = _logic;}
        private void somethingChaged1() {isTyping.setText("loading...");System.out.println("status changed in 'loading...'");}
        private void somethingChaged2() {isTyping.setText("is done.");System.out.println("status changed in 'is done.'");}
    }

}

2 个答案:

答案 0 :(得分:2)

为了澄清我在markbernard's answer中所做的评论,这是应该如何做的:

    @Override public void keyPressed(KeyEvent e){
        if (e.getKeyCode() == KeyEvent.VK_ENTER) {
            // Change the GUI from the EDT (current thread):
            _gui.somethingChaged1();

            // start a new Thread to do the long processing:
            Thread t = new Thread(new Runnable() {
              public void run() {
                _logic.thinking();// LOGIC PROCESSING (3sec)

                // when the processing in this new Thread is complete,
                // update the GUI again via the EDT:
                SwingUtilities.invokeLater(new Runnable(){
                  public void run() {
                    _gui.somethingChaged2();
                  }
                });
              }
            }, "Logic Code");
            t.start();

            e.consume();// Stopping adding an Enter after message
        }
    }

答案 1 :(得分:0)

你的问题就在这里:

        @Override public void keyPressed(KeyEvent e){
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {

                _gui.somethingChaged1();// CHANGE 1 GUI
                _logic.thinking();// LOGIC PROCESSING (3sec)
                _gui.somethingChaged2();// CHANGE 2 GUI

                e.consume();// Stopping adding an Enter after message
            }
        }

您正在事件派发线程中执行长时间运行的功能。 GUI在事件调度线程中更新,因此在您退出侦听器之前,不会看到GUI更改。试试这个:

        @Override public void keyPressed(KeyEvent e){
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                Thread t = new Thread(new Runnable() {
                  _gui.somethingChaged1();// CHANGE 1 GUI
                  public void run() {
                    _logic.thinking();// LOGIC PROCESSING (3sec)
                    //Changed based on comment from daiscog
                    SwingUtilities.invokeLater(new Runnable() {
                      public void run() {
                        _gui.somethingChaged2();// CHANGE 2 GUI
                      }
                    });
                  }
                }, "Logic Code");
                t.start();

                e.consume();// Stopping adding an Enter after message
            }
        }

为线程命名也是一个很好的做法,所以如果你必须调试,你可以很容易地找到你创建的线程。