Java ActionListener无法处理JMenuItem

时间:2017-06-11 00:24:33

标签: java swing actionlistener menuitem

我遇到一些无法正常工作的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 ,但它只适用于在控制台中编写,它不能运行预期的方法。我还必须提一下,如果在类构造函数中调用了 StartDemo StartRandom 方法,但是如果在动作侦听器方法中调用它们,它们就会冻结应用程序。此外,该应用程序甚至冻结了 StartCustom 方法,它几乎没有。

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

1 个答案:

答案 0 :(得分:1)

仅供参考:您已ActionListener添加到customStartCustom调用StartDemoprivate void Game() { while (world.CountAliveCells() > 0) { world.UpdateCellNeighbors(); world.UpdateTable(); try { Thread.sleep(700); } catch (InterruptedException e) { e.printStackTrace(); } } } ,可能不是您的意图

关于你的实际问题......

  

应用程序冻结,我无法执行任何其他操作,只需将其从Eclipse停止按钮停止

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

如果我们仔细看看你的代码......

Game

我们可以看到Game正在运行循环。由于ActionListener是在actionPerformed Timer方法的上下文中调用的,因此可以保证在事件调度线程的上下文中调用它,表示EDT不再运行,无法再处理事件队列中的任何新事件。

有关详细信息,请参阅Concurrency in Swing

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

当选择解决方案来解决这个问题时 - 请记住,Swing不是线程安全的,这意味着对UI的任何更新必须在EDT的上下文中进行。 Swing ActionListener虽然简单,但会在EDT的上下文中触发已注册的actionPerformed function my_custom_address () { $listing_address_country = get_my_field( 'address_country' ); $listing_address_city = get_my_field( 'address_city' ); // Setting array values $arrayValue='<span class="my-address-country">' . $listing_address_country . '</span><span class="my-address-city">' . $listing_address_city . '</span>'; $formats = array( 'default' =>$arrayValue ); return $formats; } // Now call your function $my_custom_address=my_custom_address(); // You can use it any were // To echo the return data do foreach($my_custom_address as $data){ echo $data; } 方法,使其成为安全选项