如何输出到GUI,暂停,然后输出其他内容(例如使用SwingWorker)?

时间:2014-10-20 23:15:40

标签: java swingworker

我正在用Java制作一个简单的基于文本的回合制战斗游戏(作为一种学习练习,所以我试图理解我所做的一切)并且我想模拟对手转弯。这主要涉及打印出一条消息(例如" Enemy&#t; s"),处理敌人的转弯,暂停(用Thread.sleep),然后打印出另一条消息( "例如"轮到你了#34;)。

我的GUI是一个带有Swing元素的JApplet类,但这是因为它很容易制作和理解,而不是因为我对使用Swing有任何附件。我没有多线程的经验,但已经读过SwingWorker在这种情况下很有用(在漫长的后台进程运行时更新Swing GUI)。这是一个没有实际游戏代码的版本,为了简单起见,它们都包含在同一个类中:

public class SimpleGame extends JApplet implements ActionListener {
    private Game game;
    private String inputCommand;
    private JTextArea textOutput;
    private JTextField inputField;
    public void init() {
        textOutput = new JTextArea();
        DefaultCaret caret = (DefaultCaret) textOutput.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
        textOutput.setEditable(false);
        Container window = getContentPane();
        window.setLayout(new BorderLayout());
        window.add(textOutput, BorderLayout.CENTER);
        JButton submitButton = new JButton("Submit");
        submitButton.addActionListener(this);
        inputField = new JTextField(20);
        inputField.addActionListener(this);
        JPanel inputPanel = new JPanel();
        inputPanel.add(inputField);
        inputPanel.add(submitButton);
        window.add(inputPanel, BorderLayout.SOUTH);
        inputField.requestFocusInWindow();
        game = new Game();
    }
    public class GuiUpdater extends SwingWorker<Boolean, String> {
        private String command;
        public GuiUpdater(String inputCommand) {
            super();
            command = inputCommand;
        }
        public void publish(String chunk) {
            super.publish(chunk);
        }
        protected Boolean doInBackground() throws Exception {
            Output.setWorker(this);
            boolean successfulCommand = game.performCommand(command);
            return successfulCommand;
        }
        protected void process(List<String> chunks) {
            for (String chunk : chunks) {
                textOutput.append(chunk);
            }
        }
    }
    public void actionPerformed(ActionEvent event) {
        if (game.isItYourTurn()) {
            inputCommand = inputField.getText();
            if (inputCommand.length() != 0) {
                GuiUpdater worker = new GuiUpdater(inputCommand);
                worker.execute();
                boolean successfulCommand;
                try {
                    successfulCommand = worker.get();
                } catch (InterruptedException | ExecutionException e) {
                    successfulCommand = false;
                }
                if (!successfulCommand) {
                    textOutput.append("Invalid command.\n");
                }
                inputField.setText("");
            }
        } else {
            textOutput.append("\nWait for your turn!\n");
        }
    }
    private static class Output {
        private static GuiUpdater worker;
        static void setWorker(GuiUpdater newWorker) {
            worker = newWorker;
        }
        static void update(String updateText) {
            worker.publish(updateText);
        }
    }
    private class Game {
        private boolean yourTurn;
        public Game() {
            yourTurn = true;
        }
        public boolean isItYourTurn() {
            return yourTurn;
        }
        public boolean performCommand(String inputString) throws InterruptedException {
            yourTurn = false;
            // perform player action
            Output.update("\nEnemy turn");
            Thread.sleep(1000);
            // perform enemy action
            Output.update("\nYour turn");
            yourTurn = true;
            return true;
        }
    }
}

不幸的是,不是输出一行,等待一秒,然后输出第二行,所有行都在所有睡眠结束后输出到Swing GUI。如果我用Output.update("text")替换我的System.out.println("text"),那么时间按预期工作,但显然我不想仅仅依靠我的游戏控制台输出。

如果有人对我做错了什么或者在输出之间暂停的替代方法有任何解释,我们将不胜感激。干杯!

1 个答案:

答案 0 :(得分:1)

你对worker.get()的调用阻止了swing-applet线程,直到worker完成。您需要将结果的处理移动到SwingWorker done()方法中,该方法在doInBackground()方法完成之前不会执行。代码的那部分应该如下所示:

public class GuiUpdater extends SwingWorker<Boolean, String> {
    private String command;

    public GuiUpdater(String inputCommand) {
        super();
        command = inputCommand;
    }

    public void publish(String chunk) {
        super.publish(chunk);
    }

    @Override
    protected Boolean doInBackground() throws Exception {
        Output.setWorker(this);
        boolean successfulCommand = game.performCommand(command);
        return successfulCommand;
    }

    @Override
    protected void process(List<String> chunks) {
        for (String chunk : chunks) {
            textOutput.append(chunk);
        }
    }

    @Override
    protected void done() {
        boolean successfulCommand;
        try {
            successfulCommand = get();
        } catch (InterruptedException | ExecutionException e) {
            successfulCommand = false;
        }
        if (!successfulCommand) {
            textOutput.append("Invalid command.\n");
        }
        inputField.setText("");
    }
}

@Override
public void actionPerformed(ActionEvent event) {
    if (game.isItYourTurn()) {
        inputCommand = inputField.getText();
        if (inputCommand.length() != 0) {
            GuiUpdater worker = new GuiUpdater(inputCommand);
            worker.execute();
        }
    } else {
        textOutput.append("\nWait for your turn!\n");
    }
}