我的项目包含两部分:逻辑模块和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.'");}
}
}
答案 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
}
}
为线程命名也是一个很好的做法,所以如果你必须调试,你可以很容易地找到你创建的线程。