简体   繁体   English

Java ActionListener无法处理JMenuItem

[英]Java ActionListener not working on JMenuItem

I have a problem with some ActionListeners that are not working as intended. 我有一些问题,一些ActionListener没有按预期工作。 Here is the code for them: 这是他们的代码:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class GameOfLife extends JFrame implements ActionListener
{
    Timer timer = new Timer(700, this);
    Table world;
    JMenuBar menuBar;
    JMenu gameMode;
    JMenu actions;
    JMenuItem custom, demo, random, start, pause, save, load;

    public GameOfLife(int width, int height)
    {
        super();
        world = new Table(width, height);
        CreateMenu();

        this.setContentPane(world);
        this.setJMenuBar(menuBar);
        this.setPreferredSize(new Dimension(1200, 900));
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.pack();
        StartRandom();
    }

    private void CreateMenu()
    {
        menuBar = new JMenuBar();
        gameMode = new JMenu("Game Mode");
        actions = new JMenu("Actions");

        custom = new JMenuItem("Custom Game");
        custom.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                StartCustom();
            }
        });
        gameMode.add(custom);

        demo = new JMenuItem("Demo Game");
        demo.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                StartDemo();
            }
        });
        gameMode.add(demo);

        random = new JMenuItem("Random Game");
        random.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                StartRandom();
            }
        });
        gameMode.add(random);
        menuBar.add(gameMode);
    }

    private void Demo()
    {
        int[] x =
        {
            5, 5, 5, 5, 5, 5, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12,
            12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 17, 17, 17, 17, 17
        };
        int[] y =
        {
            7, 8, 9, 13, 14, 15, 5, 10, 12, 17, 5, 10, 12, 17, 5, 10, 12, 17, 7, 8, 9, 13, 14, 15, 7, 8, 9,
            13, 14, 15, 5, 10, 12, 17, 5, 10, 12, 17, 5, 10, 12, 17, 7, 8, 9, 13, 14, 15
        };
        int i = 0;
        while (i < x.length)
        {
            world.SetStartPosition(x[i], y[i++]);
        }
    }

    private void StartCustom()
    {
        // TO-DO
    }

    private void StartDemo()
    {
        Demo();
        Game();
    }

    private void StartRandom()
    {
        world.RandomTable();
        Game();
    }

    private void Game()
    {
        while (world.CountAliveCells() > 0)
        {
            timer.start();
        }
    }

    public static void main(String[] args) {
        new GameOfLife(20,20);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        world.UpdateCellNeighbors();
        world.UpdateTable();
    }

}

When I press one of the menu items from the gameMode menu, the application freezes and I can't do anything else but just stop it from the Eclipse stop button. 当我按下gameMode菜单中的一个菜单项时,应用程序冻结,我不能做任何其他事情,只是从Eclipse停止按钮停止它。 I also tried with addMouseListener but it works only for writing in console, it dose not run the intended method. 我也试过addMouseListener,但它只适用于在控制台中编写,它不能运行预期的方法。 I also must mention that the StartDemo and StartRandom methods work if called in the class constructor but they just freeze the application if called in the action listener method. 我还必须提一下,如果在类构造函数中调用StartDemoStartRandom方法,它们只会在动作侦听器方法中调用时冻结应用程序。 Also, the application freezes even for the StartCustom method which does literally nothing. 此外,即使对于几乎没有任何内容的StartCustom方法,应用程序也会冻结。

EDIT: I changed the Thread.sleep function with a Swing Timer and the problem is still the same. 编辑:我用Swing Timer更改了Thread.sleep函数,问题仍然相同。 The application still freezes when I try to select a game mode from the menu button but it works perfectly when the StartDemo or StartRandom methods are called from the class constructor. 当我尝试从菜单按钮中选择游戏模式时,应用程序仍会冻结,但是当从类构造函数调用StartDemo或StartRandom方法时,它可以正常工作。

FYI: You've added to ActionListener s to custom which calls StartCustom and StartDemo , probably not what you intended 仅供参考:您已将ActionListener添加到调用StartCustomStartDemo custom中,可能不是您想要的

As to your actual problem... 至于你的实际问题......

the application freezes and I can't do anything else but just stop it from the Eclipse stop button 应用程序冻结,我不能做任何其他事情,只是从Eclipse停止按钮停止它

In Swing, this means you've blocked the Event Dispatching Thread in some way 在Swing中,这意味着您已经以某种方式阻止了事件调度线程

If we take a closer look at your code... 如果我们仔细看看你的代码......

private void Game()
{
    while (world.CountAliveCells() > 0)
    {
        world.UpdateCellNeighbors();
        world.UpdateTable();
        try {
            Thread.sleep(700);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

we can see Game is running a loop. 我们可以看到Game正在运行循环。 Because Game is called from within the context of the ActionListener 's actionPerformed method, it's guaranteed to be called within the context of the Event Dispatching Thread, which means that the EDT is no longer going to be running and can no longer process any new events in the Event Queue. 因为Game是在ActionListeneractionPerformed方法的上下文中调用的,所以它保证在Event Dispatching Thread的上下文中被调用,这意味着EDT不再运行并且不能再处理任何新事件在事件队列中。

See Concurrency in Swing for more details. 有关更多详细信息,请参阅Swing中的并发

There are number of ways you might be able to change this to work, the simplest would be to use a Swing Timer , see How to use Swing Timers for more details. 您可以通过多种方式更改此功能,最简单的方法是使用Swing Timer ,有关详细信息,请参阅如何使用Swing Timers

When choosing a solution to solve this problem - remember, Swing is NOT thread safe, this means that any updates to the UI MUST be made from within the context of the EDT. 当选择解决方案来解决这个问题时 - 记住,Swing不是线程安全的,这意味着对UI的任何更新必须在EDT的上下文中进行。 Swing Timer , while simple, triggers the registered ActionListener s actionPerformed method within the context of the EDT, making it a safe option Swing Timer虽然简单,但在EDT的上下文中触发已注册的ActionListeneractionPerformed方法,使其成为一个安全的选项

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM