我知道应该使用invokeLater在事件调度线程(EDT)上安全地创建JFrame,并且我试图在我的main方法中创建其中两个。
public void run() {
// Handle Menu When Open
menu.setVisible(true);
while(menu.isVisible())
{
if(menu.isShowing() == false) {
showMenu = false;
showSimulation = true;
}
}
menu.setVisible(false);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
int[] dims = menu.SizeSetting();
simulation = new Simulation(dims[0], dims[1]);
}
});
simulation.run();
}
因此,菜单已创建(这似乎工作正常,因为此处所需的处理非常少)。在此之后,使用菜单,在menu.setVisible(false)
处单击按钮被调用。之后,我在EDT上排队一个方法,Simulation是一个派生自JFrame
的类。它的构造函数如下:
public Simulation(int width, int height) {
this.setVisible(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Traffic Light System - Simulation");
grid = new Grid(0, 0);
ready = false;
grid = new Grid(width, height);
addComponentsToPane(); // Set up visualization of grid here
// Introduce cars here? e.g. grid.Get(0, 0).addCars(new Car[])?
ready = true;
setVisible(true);
}
addComponentsToPane()
方法将所有必要内容添加到JFrame。在此构造函数之后调用的run()方法只是:
public void Run() {
while(isVisible()) {
OneStep();
}
setVisible(false);
}
但是,当我运行此代码时,我只看到菜单窗口。当我退出菜单,并且应该显示模拟窗口时 - 程序似乎已关闭。
我在这里做错了什么想法?
答案 0 :(得分:6)
即使我不完全明白你想要做什么,但我可以毫无疑问地说你错了。您的while (true)
循环不应该存在,不应该存在于事件驱动的系统中,并且相信事件驱动编程的概念。相反,您的代码应该由于对事件的反应而改变状态,而不是在循环时永远不会结束。
另请注意,您的代码可能会在创建之前调用模拟方法。请注意,它是在调用Run方法(应该命名为run)的不同线程中创建的,并且您无法保证执行顺序,并且实际上可能发生了错误的顺序,因为调用Runnable会有延迟代码,因为它首先必须在被调用之前排队到事件线程。
为了更好的帮助,请考虑创建并发布一个minimal, compilable, runnable program,向我们展示您的问题。
编辑1
此外,您还需要学习和使用Java命名约定,包括以大写字母开头的类名以及以小写字母开头的方法和变量名。
编辑2 你说:
虽然基本上这个实例化完成后 - 所有程序都会自行更新而不进行任何交互。这就是循环的想法。循环将更新模拟,然后更新正在显示的内容。
如果您正在尝试运行Swing模拟,那么为什么不简单地使用Swing Timer进行动画循环?您的代码几乎可以保证导致Swing线程发生错误。
编辑3
在第3或第4次阅读时,在我看来,您正试图从主应用程序以模式方式显示菜单视图 - 即当菜单处于活动状态时,主应用程序无法交互或不可见。如果是这样,请考虑,1)在菜单窗口中使用模态JDialog。这样您就可以启动窗口,启动代码将在此位置暂停,直到菜单窗口不再可见。然后,您可以显示动画窗口。或者2)使用CardLayout交换视图。这里有一个JFrame应用程序,最初显示您的菜单JPanel。然后,当处理完菜单后,您将拥有CardLayout交换视图,以便现在动画显示在其位置。