我有一个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:
天哪,对不起,我真的不知道如何缩短它,但你只需要查看Game
和Gui
,其他人就可以编译。< / p>
代码:https://gist.github.com/anonymous/53bad714592792316b4d
要测试的xml:https://gist.github.com/anonymous/30b56facb78fe6ecd482
答案 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
。它的布局要少一个
;)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);
嗯,我很好奇,我真的想测试你的游戏(顺便说一句非常好的工作:)事情是我在逻辑中发现了至少两个问题:
==
来比较字符串在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。