有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

当扫描仪等待用户输入时,java GUI冻结

我意识到,您需要使用事件调度线程来避免冻结和死锁,但现在我来讨论冻结问题。我怀疑我有这个问题是因为封装的EDT

这是一个包含主要静态方法的类:

@SuppressWarnings("serial")
public class WelcomeScreen extends JFrame implements ActionListener {

/*
 * initialize variables
 */
private JButton btnSubmit;
private JTextField nameInput;
private JLabel enterName;

public WelcomeScreen() {

    /*
     * build the welcome frame with all components
     */
    setAlwaysOnTop(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setResizable(false);
    setBounds(0, 0, 514, 256);
    getContentPane().setLayout(null);

    // welcome label
    JLabel label_welcome = new JLabel("<html>Welcome to <br/>Game</html>");
    label_welcome.setHorizontalAlignment(SwingConstants.CENTER);
    label_welcome.setBounds(159, 11, 190, 32);
    getContentPane().add(label_welcome);

    // create the warrior button
    btnSubmit = new JButton("Start");
    btnSubmit.setBounds(209, 129, 89, 23);
    btnSubmit.addActionListener(this);
    btnSubmit.setFocusable(false);
    getContentPane().add(btnSubmit);

    enterName = new JLabel("Enter Player Name:");
    enterName.setBounds(50, 60, 150, 50);
    getContentPane().add(enterName);

    nameInput = new JTextField();
    nameInput.setBounds(212, 70, 125, 25);
    getContentPane().add(nameInput);

    // set frame visible
    setVisible(true);

}

/*
 * action listener
 */
public void actionPerformed(ActionEvent evt) {

    if (evt.getSource().equals(btnSubmit)) {
        dispose();
        new Core();
    }

}

/*
 * <<<<<MAIN STATIC METHOD>>>>>
 */
public static void main(String[] args) {

    // safely start the welcome frame
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            new WelcomeScreen();
        }
    });

}
}

这是扩展JFrame的第二个类。这是冻结的GUI。如果查看gameEngine()方法,您会注意到字符串输入=键盘。next(),导致冰冻。如果这一行被注释掉,GUI将显示两个字符串“test1”和“test2”

@SuppressWarnings("serial")
public class Core extends JFrame {

/*
 * initialize variables
 */
private Scanner keyboard;
private JTextArea textArea;

public Core() {

    /*
     * create the frame that displays output messages
     */
    setBounds(0, 0, 800, 400);
    setResizable(false);
    setLocationRelativeTo(null);
    setAlwaysOnTop(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    getContentPane().setLayout(null);

    JPanel panel = new JPanel();
    panel.setBounds(10, 11, 774, 349);
    panel.setLayout(null);
    getContentPane().add(panel);

    textArea = new JTextArea();
    JScrollPane scroll = new JScrollPane(textArea);
    scroll.setBounds(0, 0, 774, 349);
    textArea.setBounds(10, 11, 443, 279);
    panel.add(scroll);

    // THIS ISN'T EVEN SHOWING UP
    appendMessage("test1");

    // set frame visible
    setVisible(true);

    // NEITHER IS THIS
    appendMessage("test2");

    /*
     * start game engine
     */
    gameEngine();

}

/*
 * start gameEngine
 */
public void gameEngine() {

    // instantiate scanner
    keyboard = new Scanner(System.in);

    // <<<<<<<<<<<<<<<THIS HERE IS CAUSING THE GUI TO FREEZE>>>>>>>>>>>>>>>
    String input = keyboard.next();

}

// append a message to the GUI
public void appendMessage(String s) {
    textArea.append("> " + s + "\n");
}

}

共 (2) 个答案

  1. # 1 楼答案

    您的问题是,扫描仪正在阻止Swing事件线程,从而阻止GUI绘制和与用户交互。一个简单的解决方案是在后台线程中进行扫描仪交互。更好的解决方案是完全摆脱扫描仪(System.in),通过GUI实现所有用户交互。控制台I/O和GUI I/O不应混合使用

    使用JTextField和布局管理器获取并响应输入的一个简单示例:

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.KeyEvent;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class Fu22GamePanel extends JPanel {
        private static final int COLS = 50;
        private static final int ROWS = 25;
        private static final int GAP = 3;
        private JTextField entryField = new JTextField(COLS);
        private JTextArea textArea = new JTextArea(ROWS, COLS);
        private String playerName;
    
        public Fu22GamePanel(String name) {
            this.playerName = name;
            textArea.setFocusable(false);
            textArea.setWrapStyleWord(true);
            textArea.setLineWrap(true);
            JScrollPane scrollPane = new JScrollPane(textArea);
            scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    
            EntryAction entryAction = new EntryAction("Submit", KeyEvent.VK_S);
            entryField.setAction(entryAction);
            JPanel bottomPanel = new JPanel();
            bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS));
            bottomPanel.add(entryField);
            bottomPanel.add(new JButton(entryAction));
    
            setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
            setLayout(new BorderLayout(GAP, GAP));
            add(scrollPane);
            add(bottomPanel, BorderLayout.PAGE_END);
        }
    
        private class EntryAction extends AbstractAction {
            public EntryAction(String name, int mnemonic) {
                super(name);
                putValue(MNEMONIC_KEY, mnemonic);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                String text = entryField.getText();
                entryField.setText("");
                textArea.append("> " + text + "\n");
                entryField.requestFocusInWindow();
            }
        }
    
        private static class WelcomePanel extends JPanel {
            private JTextField playerNameField = new JTextField(10);
    
            public WelcomePanel() {
                int wpGap = 20;
                setBorder(BorderFactory.createEmptyBorder(wpGap, wpGap, wpGap, wpGap));
                add(new JLabel("Enter Player Name:"));
                add(playerNameField);
            }
    
            public String getPlayerName() {
                return playerNameField.getText();
            }
        }
    
        private static void createAndShowGui() {
            WelcomePanel welcomePanel = new WelcomePanel();
            int response = JOptionPane.showConfirmDialog(null, welcomePanel, "Welcome to the Game", JOptionPane.OK_CANCEL_OPTION);
            if (response != JOptionPane.OK_OPTION) {
                return;
            }
    
            String name = welcomePanel.getPlayerName();
    
            Fu22GamePanel mainPanel = new Fu22GamePanel(name);
    
            JFrame frame = new JFrame("Game   Player: " + name);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
    
    
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> {
                createAndShowGui();
            });
        }
    }
    
  2. # 2 楼答案

    使用一个JTextField作为输入,再加上一个ActionListener,您可以对适当的事件做出响应,比如输入键

    使用JTextArea作为输出

    Bad Adventure

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class NastyAdventure {
    
        public static void main(String[] args) {
            new NastyAdventure();
        }
    
        public NastyAdventure() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JTextArea output;
            private JTextField input;
    
            private boolean isDead = false;
    
            public TestPane() {
                setLayout(new BorderLayout());
                output = new JTextArea(10, 30);
                input = new JTextField(20);
                add(new JScrollPane(output));
                add(input, BorderLayout.SOUTH);
    
                output.setEditable(false);
                output.append("A bear appears on the trial in front of you\n");
                output.append("What do you do?");
    
                input.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        input.setText(null);
                        if (!isDead) {
                            output.append("\nThe bear eats you, you die\n");
                            output.append("The adventure is over, the bear wins\n");
                        } else {
                            output.append("You're dead, you can't do anything\nThe adventure is over, the bear wins\n");
                        }
                        isDead = true;
                    }
                });
            }
    
        }
    
    }
    

    查看How to Use Text FieldsHow to Use Text AreasHow to Write an Action ListenersWriting Event Listeners了解更多详细信息

    你可能还想看看Model-View-Controller,这将帮助你保持游戏的状态,使其与UI分离