Reputation: 33
I have a problem with some ActionListeners that are not working as intended. 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. I also tried with addMouseListener but it works only for writing in console, it dose not run the intended method. 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. Also, the application freezes even for the StartCustom method which does literally nothing.
EDIT: I changed the Thread.sleep function with a Swing Timer and the problem is still the same. 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.
Upvotes: 3
Views: 360
Reputation: 347184
FYI: You've added to ActionListener
s to custom
which calls StartCustom
and StartDemo
, probably not what you intended
As to your actual problem...
the application freezes and I can't do anything else but just stop it from the Eclipse stop button
In Swing, this means you've blocked the Event Dispatching Thread in some way
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. 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.
See Concurrency in Swing for more details.
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.
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 Timer
, while simple, triggers the registered ActionListener
s actionPerformed
method within the context of the EDT, making it a safe option
Upvotes: 1