Java ActionListener not working on JMenuItem

I have a problem with some ActionListeners not working as expected. Here's 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 click on one of the menu items from the gameMode menu , the application freezes and I can't do anything other than just stop it from the Eclipse stop button. I also tried with addMouseListener , but it only works for writing to the console, but the dose is not triggered as intended. I should also mention that the StartDemo and StartRandom methods work when called in the class constructor, but they just freeze the application if called in an action listener method. In addition, the application hangs even for the StartCustom method , which literally does nothing.

EDIT: I changed the Thread.sleep function with a Swing timer and the problem is still the same. The app still hangs when I try to select the game mode from the menu button, but it works fine when the StartDemo or StartRandom methods are created from the class.

+3


source to share


1 answer


FYI: you added to ActionListener

in custom

, which is calling StartCustom

and StartDemo

may not be what you intended

As for your real problem ...

the app freezes and I cant do anything but stop it from the Eclipse stop button

In Swing, this means you have blocked the Thread Dispatching Thread somehow

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 see what Game

the loop is doing. Because it Game

is called from within the context of the method ActionListener

actionPerformed

, it is guaranteed to be called in the context of the Dispatching Event thread, which means the EDT will no longer work and can no longer handle any new events in the event queue.

See Concurrency in Swing for details .

There are several ways to change this to work, the easiest is to use Swing Timer

, see How to Use Swing Timers for more details.

When choosing a solution to solve this problem, remember that Swing is not thread safe, which means that any updates to the UI MUST be made from within the EDT context. Swing Timer

, while simple, runs the registered method ActionListener

actionPerformed

in the EDT context, making it a safe option

+1


source







All Articles