【问题标题】:Java Swing Thread Safety and EDTJava Swing 线程安全和 EDT
【发布时间】:2014-03-31 13:29:21
【问题描述】:

我了解应该使用 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);
}

但是,当我运行此代码时,我只看到菜单窗口。当我退出菜单并显示模拟窗口时 - 程序似乎已关闭。

有什么想法我在这里做错了吗?

【问题讨论】:

  • Run() 主方法中,simulation 变量也存在竞争条件。如果您调用invokeLater(),则该代码可能在调用simulation.Run() 方法后运行良好。结果将是不确定的。也许正确的做法是使用 invokeAndWait() 而不是 invokeLater(),但正如 Hovercraft 所指出的那样,这很难知道。

标签: java swing jframe event-dispatch-thread invokelater


【解决方案1】:

即使我不完全理解你想要做什么,我可以毫无疑问地说你做错了。您的 while (true) 循环不应该存在,不应该存在于事件驱动的系统中,并且与事件驱动编程的概念背道而驰。相反,您的代码应该由于对事件的反应而改变状态,而不是这个永无止境的 while 循环。

另请注意,您的书面代码可能会在模拟方法创建之前调用该方法。请注意,它是在调用 Run 方法(应该命名为 run)的不同线程中创建的,您不能保证执行顺序,实际上可能会发生错误的顺序,因为调用 Runnable 会有延迟代码,因为它首先必须在被调用之前排队到事件线程中。

为了获得更好的帮助,请考虑创建并发布一个minimal, compilable, runnable program,向我们展示您的问题。


编辑 1
此外,您还需要学习和使用 Java 命名约定,包括以大写字母开头的类名以及以小写字母开头的方法和变量名。


编辑 2 你说:

虽然基本上一旦这个实例化完成 - 程序所做的只是在没有任何交互的情况下更新自己。这就是循环的想法。循环将更新模拟,进而更新正在显示的内容。

如果您正在尝试运行 Swing 模拟,那么为什么不简单地将 Swing Timer 用于您的动画循环呢?您的代码几乎肯定会导致 Swing 线程故障。


编辑 3
在第 3 次或第 4 次阅读时,在我看来,您正试图从主应用程序以模态方式显示菜单视图——即当菜单处于活动状态时,主应用程序要么不可交互,要么不可见。如果是这样,请考虑,1)为您的菜单窗口使用模态 JDialog。这样您就可以启动窗口,启动代码将在此位置停止,直到菜单窗口不再可见。然后您可以显示您的动画窗口。或者 2) 使用 CardLayout 交换视图。在这里,您有一个最初显示菜单 JPanel 的 JFrame 应用程序。然后在处理完菜单后,您将拥有 CardLayout 交换视图,以便现在动画显示在它的位置。

【讨论】:

  • 很公平。虽然基本上一旦这个实例化完成 - 程序所做的就是在没有任何交互的情况下更新自己。这就是循环的想法。循环将更新模拟,进而更新正在显示的内容。
  • @fanatic:请参阅编辑以回答。同样,考虑创建一个minimal, compilable, runnable program 供我们测试和修改。
  • @fanatic: 还有编辑3
猜你喜欢
  • 1970-01-01
  • 2011-10-13
  • 2023-03-16
  • 2013-08-21
  • 2013-01-20
  • 2015-05-16
  • 2012-08-21
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多