扫描程序等待用户输入时GUI冻结

Dra*_*eel 1 java user-interface swing multithreading

我意识到你需要使用Event Dispatch Thread来避免冻结和死锁,但在这里,我遇到了冻结问题.由于封装的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();
        }
    });

}
}
Run Code Online (Sandbox Code Playgroud)

这是扩展JFrame的第二个类.这是冻结的GUI.如果你看一下gameEngine()方法,你会注意到String input = keyboard.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");
}

}
Run Code Online (Sandbox Code Playgroud)

Hov*_*els 5

您的问题是扫描程序阻止了Swing事件线程,阻止您的GUI绘制和与用户交互.一个简单的解决方案是在后台线程中执行Scanner交互.更好的解决方案是完全摆脱Scanner(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();
        });
    }
}
Run Code Online (Sandbox Code Playgroud)