【问题标题】:Java ActionListener not working on JMenuItemJava ActionListener 不适用于 JMenuItem
【发布时间】:2017-06-11 00:24:33
【问题描述】:

我遇到了一些无法按预期工作的 ActionListener 的问题。这是他们的代码:

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();
    }

}

当我按下 gameMode 菜单中的一个菜单项时,应用程序会冻结,我无法执行任何其他操作,只能通过 Eclipse 停止按钮将其停止。我也尝试使用 addMouseListener 但它仅适用于在控制台中编写,它不会运行预期的方法。我还必须提到,如果在类构造函数中调用 StartDemoStartRandom 方法可以工作,但如果在动作侦听器方法中调用它们只会冻结应用程序。此外,即使对于实际上什么都不做的 StartCustom 方法,应用程序也会冻结。

编辑: 我用 Swing Timer 更改了 Thread.sleep 函数,问题还是一样。当我尝试从菜单按钮选择游戏模式时,应用程序仍然冻结,但当从类构造函数调用 StartDemo 或 StartRandom 方法时,它可以正常工作。

【问题讨论】:

  • 仅供参考:您已将 ActionListeners 添加到 custom,其中调用 StartCustomStartDemo,可能不是您想要的
  • 方法名称不应以大写字符开头。向我展示一个来自 Java API 的方法。遵循 Java 约定。

标签: java swing actionlistener menuitem


【解决方案1】:

仅供参考:您已将ActionListeners 添加到custom,这调用StartCustomStartDemo,可能不是您想要的

至于你的实际问题...

应用程序冻结,我不能做任何其他事情,只能从 Eclipse 停止按钮停止它

在 Swing 中,这意味着您以某种方式阻止了事件调度线程

如果我们仔细查看您的代码...

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

我们可以看到Game 正在运行一个循环。因为Game 是在ActionListeneractionPerformed 方法的上下文中调用的,所以可以保证在事件调度线程的上下文中调用它,这意味着EDT 将不再运行并且可以不再处理事件队列中的任何新事件。

更多详情请见Concurrency in Swing

您可以通过多种方式将其更改为工作,最简单的方法是使用 Swing Timer,有关详细信息,请参阅 How to use Swing Timers

在选择解决此问题的解决方案时 - 请记住,Swing 不是线程安全的,这意味着对 UI 的任何更新都必须在 EDT 的上下文中进行。 Swing Timer 虽然简单,但会在 EDT 的上下文中触发注册的 ActionListeners actionPerformed 方法,使其成为一个安全的选择

【讨论】:

    猜你喜欢
    • 2013-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多