简体   繁体   English

JFrame无法实时更新

[英]JFrame not updating in real time

My project contain two parts: a logical modules and a gui interface. 我的项目包含两个部分:逻辑模块和gui接口。 Both send their references to other. 两者都将其引用发送给其他人。

I have an Key Listener when user sent a message. 用户发送消息时,我有一个Key Listener。 In this listener I call same gui changes before logic and same changes after logic. 在此侦听器中,我称逻辑更改之前的gui更改和逻辑更改之后的相同更改。 The problem is both changes will be display at the same time, at the end of execution. 问题是两个更改将在执行结束时同时显示。

How to force the GUI update in real time? 如何强制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.'");}
    }

}

Just to clarify the comment I made in markbernard's answer , this is how it should be done: 只是为了澄清我在markbernard的回答中所作的评论,这是应该这样做的:

    @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
        }
    }

Your problem is right here: 您的问题就在这里:

        @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
            }
        }

You are performing long running fuctions in the event dispatch thread. 您正在事件分配线程中执行长时间运行的功能。 GUIs update in the event dispatch thread so until you exit your listener no GUI changes will be seen. GUI在事件调度线程中进行更新,因此在退出侦听器之前,不会看到GUI更改。 Try this: 尝试这个:

        @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
            }
        }

It's also a good practice to name your threads so if you have to debug you can easily find the threads you created. 命名线程也是一个好习惯,因此,如果必须调试,可以轻松找到创建的线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM