Java 扫描仪等待用户输入时GUI冻结

Java 扫描仪等待用户输入时GUI冻结,java,multithreading,swing,user-interface,Java,Multithreading,Swing,User Interface,我意识到您需要使用事件调度线程来避免冻结和死锁,但现在我来谈谈冻结问题。我怀疑我有这个问题是由于封装的EDT 这是具有主要静态方法的类: @SuppressWarnings("serial") public class WelcomeScreen extends JFrame implements ActionListener { /* * initialize variables */ private JButton btnSubmit; private JTextField nameI

我意识到您需要使用事件调度线程来避免冻结和死锁,但现在我来谈谈冻结问题。我怀疑我有这个问题是由于封装的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();
        }
    });

}
}
@SuppressWarnings(“串行”)
公共类WelcomeScreen扩展JFrame实现ActionListener{
/*
*初始化变量
*/
私人JButton btnSubmit;
私有JTextField name输入;
私有JLabel enterName;
公众福利屏幕(){
/*
*使用所有组件构建欢迎框架
*/
setAlwaysOnTop(真);
setDefaultCloseOperation(关闭时退出);
setLocationRelativeTo(空);
可设置大小(假);
立根(0,0,514,256);
getContentPane().setLayout(null);
//欢迎标签
JLabel label_welcome=新的JLabel(“欢迎来到
游戏”); label_welcome.setHorizontalAlignment(SwingConstants.CENTER); 标签(159,11,190,32),; getContentPane().add(label_welcome); //创建战士按钮 btnSubmit=新的JButton(“开始”); btnsubunds(209129 89 23); btnSubmit.addActionListener(此); btnSubmit.setFocusable(false); getContentPane().add(btnSubmit); enterName=新的JLabel(“输入玩家名称:”); enterName.setBounds(50,60,150,50); getContentPane().add(enterName); nameInput=新的JTextField(); nameInput.setBounds(212,70,125,25); getContentPane().add(nameInput); //设置帧可见 setVisible(真); } /* *动作监听器 */ 已执行的公共无效操作(操作事件evt){ if(evt.getSource().equals(btnSubmit)){ 处置(); 新核心(); } } /* * */ 公共静态void main(字符串[]args){ //安全启动欢迎框架 SwingUtilities.invokeLater(新的Runnable(){ 公开募捐{ 新WelcomeScreen(); } }); } }
这是扩展JFrame的第二个类。这是冻结的GUI。如果查看gameEngine()方法,您会注意到String input=keyboard.next(),导致冻结。如果这一行被注释掉,GUI将显示两个字符串“test1”和“test2”

@SuppressWarnings(“串行”)
公共类核心扩展了JFrame{
/*
*初始化变量
*/
专用扫描仪键盘;
私人JTEXTEXTAREA textArea;
公共核心(){
/*
*创建显示输出消息的框架
*/
立根(0,0,800,400);
可设置大小(假);
setLocationRelativeTo(空);
setAlwaysOnTop(真);
setDefaultCloseOperation(关闭时退出);
getContentPane().setLayout(null);
JPanel面板=新的JPanel();
嵌板.立根(10,11,774,349);
panel.setLayout(空);
getContentPane().add(面板);
textArea=新的JTextArea();
JScrollPane scroll=新的JScrollPane(textArea);
滚动.后退(0,0,774,349);
textArea.setBounds(10,11,443,279);
面板。添加(滚动);
//这甚至没有出现
附加消息(“test1”);
//设置帧可见
setVisible(真);
//这也不是
附加消息(“test2”);
/*
*启动游戏引擎
*/
游戏引擎();
}
/*
*启动游戏引擎
*/
公共游戏引擎(){
//实例化扫描仪
键盘=新扫描仪(System.in);
// 
字符串输入=键盘.next();
}
//将消息附加到GUI
公共消息(字符串s){
textArea.append(“>”+s+“\n”);
}
}

您的问题是扫描仪正在阻止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();
        });
    }
}

您的问题是,扫描仪正在阻止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();
        });
    }
}

使用
JTextField
作为输入,与
ActionListener
配合使用,您可以对适当的事件(如回车键)做出响应

使用
JTextArea
作为输出

请查看,并获取更多详细信息


您可能还想了解一下,这将有助于您将游戏状态与UI分开来维护

使用
JTextField
作为输入,再加上
ActionListener
,您可以对适当的事件(如回车键)做出响应

使用
JTextArea
作为输出

请查看,并获取更多详细信息


您可能还想看看,这将有助于您将游戏状态与UI分开来维护,原因如下。现在,您需要问“为什么?”您是否试图从GUI中的控制台获取用户输入?避免使用
null
布局,像素完美布局在现代ui设计中是一种错觉。影响零部件单个尺寸的因素太多,您无法控制。Swing的设计目的是与核心的布局管理器一起工作,丢弃它们将导致无止境的问题,您将花费越来越多的时间试图解决这些问题rectify@MadProgrammer长话短说,我正在开发一个简单的基于文本的游戏。我发现让JTextField“act”相当于控制台输入非常困难。程序不会等待JTextField输入。这就是为什么在这种情况下,美国
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;
                }
            });
        }

    }

}