2017-06-11 4 views
3

J'ai un problème avec certains ActionListeners qui ne fonctionnent pas comme prévu. Voici le code pour eux:Java ActionListener ne fonctionne pas sur JMenuItem

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

} 

Lorsque j'appuie sur l'un des éléments de menu dans le menu GameMode, l'application se bloque et je ne peux rien faire d'autre mais seulement l'arrêt du bouton d'arrêt Eclipse. J'ai également essayé avec addMouseListener mais cela fonctionne seulement pour l'écriture dans la console, il ne dose pas exécuter la méthode prévue. Je dois également mentionner que les méthodes StartDemo et StartRandom fonctionnent si elles sont appelées dans le constructeur de la classe, mais qu'elles gèlent simplement l'application si elles sont appelées dans la méthode de l'écouteur d'actions. En outre, l'application se bloque même pour la méthode StartCustom qui ne fait littéralement rien. J'ai changé la fonction Thread.sleep avec une minuterie d'oscillation et le problème est toujours le même. L'application reste figée lorsque j'essaie de sélectionner un mode de jeu à partir du bouton de menu, mais cela fonctionne parfaitement lorsque les méthodes StartDemo ou StartRandom sont appelées depuis le constructeur de la classe.

+1

Pour votre information: Vous avez ajouté à '' ActionListener's à custom' qui appelle '' StartCustom' et StartDemo', probablement pas ce que vous vouliez – MadProgrammer

+0

Les noms de méthodes ne devraient PAS commencer par un caractère majuscule. Montrez-moi une méthode de l'API Java qui le fait. Suivez les conventions Java. – camickr

Répondre

1

Pour votre information: Vous avez ajouté à ActionListener s à custom qui appelle StartCustom et StartDemo, probablement pas ce que vous aviez l'intention

Quant à votre problème réel ...

les application se bloque et je peux Ne faites rien d'autre que de l'arrêter à partir du bouton d'arrêt Eclipse

Dans Swing, cela signifie que vous avez bloqué le thread d'envoi d'événement dans certains cas. manière

Si l'on regarde de plus près votre code ...

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

nous pouvons voir Game est en cours d'exécution d'une boucle. Parce que Game est appelée dans le contexte de la méthode actionPerformed, elle est garantie d'être appelée dans le contexte du thread de distribution d'événements, ce qui signifie que l'EDT ne va plus fonctionner et ne peut plus traiter de nouveaux événements dans la file d'attente des événements.

Voir Concurrency in Swing pour plus de détails.

Il y a un certain nombre de façons dont vous pourriez être en mesure de changer cela au travail, le plus simple serait d'utiliser un Swing Timer, voir How to use Swing Timers pour plus de détails.

Lorsque vous choisissez une solution pour résoudre ce problème - rappelez-vous que Swing n'est PAS thread safe, cela signifie que toute mise à jour de l'interface utilisateur DOIT être faite dans le contexte de l'EDT. Balançoire Timer, tout simple, déclenche la méthode ActionListener de actionPerformed enregistré dans le cadre de l'EDT, ce qui en fait une option sûre