为什么这个gui没有更新?

时间:2013-12-10 10:50:35

标签: java swing user-interface

我有一个Gui和一个Game课程,我无法更新游戏中的gui。我没有使用线程,但我之前看到它更新,所以这不是问题。游戏逻辑非常简单,不需要线程。无论我如何激烈地致电repaint()revalidate(),无论我把它放在哪里,它现在都不起作用。

class Gui {

    //...

    public Gui(Game game) {
        this.game = game;
        initialize();       
    }

    private void initialize() {
        //...
        okButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                okAction(textField.getText());

                textField.setVisible(false);
                okButton.setVisible(false);
                textField.setText("");
            }           
        });
    }

    private void okAction(String input) {
        game.receiveInput(input);
    }

    public void output(String msg) {        
        textArea.append(msg + "\n");        
    }

    public void getInput() {
        textField.setVisible(true);
        okButton.setVisible(true);
        textField.setText("");      
    }
}

此外,我希望能够将String传递回游戏实例。我以为我会在游戏中调用getInput(),这会显示JTextField要输入,JButton要提交。在actionPerformed()方法中,我只需输入文本,然后在游戏类中调用方法。我不知道这是否有效,因为gui没有更新,我从未输入输入字段和按钮。这是对的吗?

这将是gui“回调”的方法:

class Game {

    //...

    public void receiveInput(String input) {
        int n = Integer.parseInt(input);
        if ( validInput(input, actualDecision.choices.size()) ) {
            parser.setAction(actualDecision.choices.get(n-1).action);
        }
    }
}

从游戏课程中,我只想几次致电gui.output()gui.getInput()

我的问题在哪里?为什么不更新,也不冻结?如果我使用调试器,则执行output()getInput(),但没有任何反应......

编辑:

好的,我自己看到了一个问题,获取输入部分...由于它快速返回,它永远不会收到输入。但这并不能解释为什么不是输入字段和按钮,或任何文本显示

编辑2:

天哪,对不起,我真的不知道如何缩短它,但你只需要查看GameGui,其他人就可以编译。< / p>

代码:https://gist.github.com/anonymous/53bad714592792316b4d

要测试的xml:https://gist.github.com/anonymous/30b56facb78fe6ecd482

1 个答案:

答案 0 :(得分:2)

老实说,我刚刚查看了Gui类代码,并且不知道为什么它与Game类交互时无法正确更新。但是我对你的代码有几点评论,我希望这些可以通过使这个类更简单,然后你可以专注于与Game类的交互来以正确的方式引导你。

菜单栏

您要将JMenuBar添加到JPanel,而不是将其设置为JFrame

panel.add(menuBar, gbc);
//frame.setJMenuBar(menuBar); Use this instead

由于JFrame是准备处理菜单栏的顶级容器,您应该考虑进行建议的更改。

保存validate()来电

JFrame方法开始时初始化initialize()并在使框架可见后添加JPanel,您必须调用frame.revalidate()方法重新验证组件层次结构如果您只是在使框架可见之前初始化面板,则无需调用revalidate()方法。请查看this answer了解更多详情。

缺少pack()来电

没有调用frame.pack()方法来布置框架的子组件。看看Window.pack()

添加GridBagConstraints

时遗失okButton

GridBagConstraints添加到okButton时,没有panel作为参数:

panel.add(okButton);
//panel.add(okButton, gbc); This is the correct way.

使用setSize()

在这一行:

frame.setSize(800, 600);

由于本主题中讨论的原因,我们应该避免使用set(Preferred | Minimum | Maximum)Size()Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

使用GridBagLayout

这只是一个建议,你如何使用GridBagLayout没有错。您可能已经注意到这个布局管理器有点难以使用(顺便说一下,我真的不喜欢它)您可以使用Nested Layout方法使组件布局更容易,代码更易读。也许这种方法足够好了:

  • JMenuBar设置为JFrame。它的布局要少一个 ;)
  • 将带有文本区域的滚动窗格直接添加到框架中 内容窗格使用 BorderLayout 约束:frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
  • 创建一个新的JPanel来保存文本字段和用于的按钮 询问用户的输入并将其添加到框架的内容窗格中。

转换为代码:

JPanel usersInput = new JPanel(new FlowLayout(FlowLayout.CENTER));
usersInput.add(textField);
usersInput.add(okButton);

frame = new JFrame();
frame.setJMenuBar(menuBar);
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.getContentPane().add(usersInput, BorderLayout.SOUTH);
frame.setTitle("Choose your own adventure");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // It's better practice DISPOSE_ON_CLOSE ;)
frame.setVisible(true); 

enter image description here


更新

嗯,我很好奇,我真的想测试你的游戏(顺便说一句非常好的工作:)事情是我在逻辑中发现了至少两个问题:

使用==来比较字符串

Parser类中,使用==进行了多次字符串比较,但这不是比较字符串的正确方法。我们必须使用.equals()方法来比较字符串相等性。请看一下这个主题:How do I compare strings in Java?

Game.processStory()有一个无限循环

这种方法在这里有无限循环:

while ( !end() ) { // this condition never is false so the loop is infinite
    ...
}

仔细观察Game.end()方法,我发现了一个不正确的字符串比较:

private boolean end() {
    return ( parser.getAction() == "end" );
    //It should be: return parser.getAction().equals("end");
}

但是修复它并不能解决问题:转为parser.getAction()总是返回"d1",因此永远不会等于"end"

Game.play()(由newGameItem菜单项触发的Event Dispatching Thread(又称EDT)中执行Game.processStory()时执行此操作并且Gui有这个无限循环,然后EDT正在获得阻止,{{1}}永远不会更新。

在这种情况下,我建议您查看Concurrency in Swing路径,了解如何避免阻止EDT。