2010-11-29 25 views
0

Je crois que la partie MVC est la plus importante pour ce programme - Game Of Life. Cependant, je n'arrive pas à faire fonctionner le MouseListener correctement. Comment puis-je changer ce match le modèle de conception MVC?Comment puis-je régler ce programme pour qu'il corresponde au modèle de conception MVC?

Voir

package lifepreparation; 
import java.awt.Color; 
import java.awt.*; 
import java.awt.event.*; 
import java.util.Hashtable; 
import javax.swing.*; 
import java.awt.event.MouseListener; 

public class LifeView extends JFrame { 
    //Label used to house cells 
    private LifeModel[][] cellHouse; 
    private LifeModel model; 

    //Timer used to fire the next generation 
    private Timer timer; 

    //Generation counter - used to count the number of generations 
    private int generationCount = 0; 
    private JLabel generationLabel = new JLabel("Generation: 0"); 

    //Declare action buttons 
    private JButton startB = new JButton("Start"); 
    private JButton pauseB = new JButton("Pause"); 
    private JButton clearB = new JButton("Clear"); 

    //Slider to adjust the time interval between generations 
    private static final int minSpeed = 0; 
    private static final int maxSpeed = 1000; 
    private static final int speedMajorTicks = (maxSpeed-minSpeed)/5; 
    private static final int speedMinorTicks = (maxSpeed-minSpeed)/20; 
    JSlider generationS = new JSlider(minSpeed,maxSpeed); 

    //Identifies game status: false=pause, true=running 
    private boolean runStatus = false; 

    //Panel for the city 
    private JPanel panel; 

    public LifeView(int boardRow, int boardCol, LifeModel model) { 
     super("Game Of Life"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     //**START Create labels to house cells, +2 more 
     cellHouse = new LifeModel[boardRow+2][boardCol+2]; 
     for(int r = 0; r < boardRow+2; r++) { 
      for(int c = 0; c < boardCol+2; c++) { 
       cellHouse[r][c] = new LifeModel(); 
      } 
    } 
     //--END Create Labels 

     //Panel to hold cell houses 
     panel = new JPanel(new GridLayout(boardRow, boardCol, 1, 1)); 
     panel.setBackground(Color.BLACK); 
     panel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); 

     //Add cellHouses to the panel 
     for(int r = 1; r < boardRow+1; r++) { 
       for(int c = 1; c < boardCol+1; c++) { 
         panel.add(cellHouse[r][c]); 
         cellHouse[r][c].addNeighbor(cellHouse[r-1][c]); //Add to TOP^
         cellHouse[r][c].addNeighbor(cellHouse[r+1][c]); //Add to BOTTOM _ 
         cellHouse[r][c].addNeighbor(cellHouse[r][c-1]); //Add to left <- 
         cellHouse[r][c].addNeighbor(cellHouse[r][c+1]); //Add to right -> 
         cellHouse[r][c].addNeighbor(cellHouse[r-1][c-1]); //Add to top left ^<- 
         cellHouse[r][c].addNeighbor(cellHouse[r-1][c+1]); //Add to top right ^-> 
         cellHouse[r][c].addNeighbor(cellHouse[r+1][c-1]); //Add to bottom left _<- 
         cellHouse[r][c].addNeighbor(cellHouse[r+1][c+1]); //Add to bottom right _-> 
       } 
     } 

     //Panel with cellHouses added to the container 
     add(panel, BorderLayout.CENTER); 

     //South Panel to hold buttons and widgets with extra features 
     JPanel panelBottom = new JPanel(); 

     //buttonPanel to hold start, pause, clear features 
     JPanel buttonPanel = new JPanel(); 

     buttonPanel.add(clearB); 
     pauseB.setEnabled(false); 
     buttonPanel.add(pauseB); 
     buttonPanel.add(startB); 

     //speedPanel to hold slider to adjust the time interval 
     JPanel speedPanel = new JPanel(); 
     JLabel speedText = new JLabel("Set Speed:"); 
     generationS.setMajorTickSpacing(speedMajorTicks); 
     generationS.setMinorTickSpacing(speedMinorTicks); 
     generationS.setPaintTicks(true); 
     // the labels for the Slider 
     Hashtable<Integer, JLabel> speedLabel = new Hashtable<Integer, JLabel>(); 
     for(int i = 0; i <= maxSpeed; i++) { 
       speedLabel.put(new Integer(i * speedMajorTicks), new JLabel("" + i)); 
     } 
     generationS.setLabelTable(speedLabel); 
     generationS.setPaintLabels(true); 


     generationLabel.setHorizontalAlignment(SwingConstants.CENTER); 

     speedPanel.add(speedText); 
     speedPanel.add(generationS); 

     panelBottom.add(buttonPanel); 
     panelBottom.add(speedPanel); 
     panelBottom.add(generationLabel); 

     // add bottom panel to the JFrame 
     add(panelBottom, BorderLayout.SOUTH); 

     // put the frame on 
     setLocation(20, 20); 
     pack(); 
     setVisible(true); 
    } 

     //Action to take dependent on the action referenced by the JButton and Timer 
     public void startPauseClear(ActionEvent e) { 
       //Get action reference 
       Object o = e.getSource(); 

       //Action reference is to clear 
       if(o == clearB) { 
         timer.stop(); //Stop the timer 
         runStatus = false; //Set game as not running 
         pauseB.setEnabled(false); //Disable the pause button 
         startB.setEnabled(true); //Enable the start button 
         //Remove/Clear all cells from the cellHouse 
         for(int r = 1; r < cellHouse.length -1; r++) { 
           for(int c = 1; c < cellHouse[r].length -1; c++) { 
             cellHouse[r][c].clear(); 
           } 
         } 
         //Reset the generation count 
         generationCount = 0; 
         generationLabel.setText("Generation: 0"); 
         return; 
       } 
       //Action reference is to pause 
       if(o == pauseB) { 
         timer.stop(); //Stop the timer 
         runStatus = false; //Set game as not running 
         pauseB.setEnabled(false); //Disable the pause button 
         startB.setEnabled(true); //Enable the start button 
         return; 
       } 
       //Action reference is to start 
       if(o == startB) { 
         pauseB.setEnabled(true); //Enable the pause button 
         startB.setEnabled(false); //Disable the start button 
         runStatus = true; //Set game as running 
         timer.setDelay(maxSpeed - generationS.getValue()); //Adjust the speed 
         timer.start(); 
         return; 
       } 

       //If the action is set by timer, set speed 
       timer.setDelay(maxSpeed - generationS.getValue()); 

       //If the game is not running, exit and do nothing more 
       if(!runStatus) return; 

       //Update generation count and display 
       ++generationCount; 
       generationLabel.setText("Generation: " + generationCount); 

       //Check to see if the cell should be buried 
       for(int r = 0; r < cellHouse.length; r++) { 
         for(int c = 0; c < cellHouse[r].length; c++) { 
           cellHouse[r][c].checkGeneration(); 
         } 
       } 

       //Update to the next generation 
       for(int r = 0; r < cellHouse.length; r++) { 
         for(int c = 0; c < cellHouse[r].length; c++) { 
           cellHouse[r][c].updateGeneration(); 
         } 
       } 
    } 
    public void addActionListener(ActionListener e) { 
     clearB.addActionListener(e); 
     pauseB.addActionListener(e); 
     startB.addActionListener(e); 
     timer = new Timer(maxSpeed - generationS.getValue(), e); 
    } 

} 

Contrôleur

package lifepreparation;  
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 

public class LifeController { 
    //Run App 
    LifeModel model; 
    LifeView view; 

    //Constructor 
    public LifeController(LifeModel model, LifeView view) { 
     this.model = model; 
     this.view = view; 

     //Add Listeners 
     view.addActionListener(new LifeActionListener()); 
     view.addMouseListener(new LifeMouseListener()); 
    } 

    class LifeActionListener implements ActionListener { 
     public void actionPerformed(ActionEvent e) { 
      view.startPauseClear(e); 
     } 
    } 

    class LifeMouseListener implements MouseListener {   
     public void mouseClicked(MouseEvent arg0) { 
      model.unselectCell(); 
     } 

     //If the mouse is in a cellHouse while being pressed, cell becomes alive 
     public void mouseEntered(MouseEvent arg0) { 
      model.selectCells(); 
     } 

     public void mouseExited(MouseEvent arg0) { 

     } 

     //If the mouse is clicked on a cellHouse, cell comes to life 
     public void mousePressed(MouseEvent arg0) { 
      model.selectACell(); 
     } 

     //Set mouse as not being held anymore 
     public void mouseReleased(MouseEvent arg0) { 
      model.setMouseHold(); 
     } 
    } 
} 

Modèle

package lifepreparation; 

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 


//LifeModel to handle cell life and death algorithm 
public class LifeModel extends JLabel { 
    //Cell Color: cell[0] = dead cell, cell[1] = live cell. 
    private static final Color[] color = {Color.LIGHT_GRAY, Color.GREEN}; 

    //Size of cells 
    private static final int cellSize = 15; 
    private static final Dimension citySize = new Dimension(cellSize, cellSize); 

    //checks if the mouse is still pressed or not 
    private boolean mouseHold = false; 

    private int currentStatus, newStatus; 
    private int nbNeighbor; 
    private LifeModel[] Neighbor = new LifeModel[8]; 

    LifeModel() { 
      currentStatus = newStatus = 0; //Currently Dead 
      setOpaque(true); //Show color 
      setBackground(color[0]); //Light Gray color 
      this.setPreferredSize(citySize); //Set the dimension of the board 
    } 
    //Add a neighbor 
    void addNeighbor(LifeModel n) { 
      Neighbor[nbNeighbor++] = n; 
    } 

    //Check to see if a cell should live or not 
    void checkGeneration() { 
      //Number of neighbors that are alive 
      int nbAlive = 0; 

      //Check the status of the neighbors 
      for(int i = 0; i < nbNeighbor; i++) 
        nbAlive += Neighbor[i].currentStatus; 

      //If status of cell is alive 
      if(currentStatus == 1) { 
        //Bury cell if it has less than two neighbors 
        if(nbAlive < 2) 
          newStatus = 0; 
        //Bury cell if it has more than three live neighbors 
        if(nbAlive > 3) 
          newStatus = 0; 
      } 
      else { 
        //Dead cells with three live neighbors get reborn 
        if(nbAlive == 3) 
          newStatus = 1; 
      } 
    } 
    //Switch to next generation 
    void updateGeneration() { 
      if(currentStatus != newStatus) { //Adjust color for the new generation 
        currentStatus = newStatus; 
        setBackground(color[currentStatus]); 
      } 
    } 

    //Bury all cells in the city 
    void clear() { 
      if(currentStatus == 1 || newStatus == 1) { 
        currentStatus = newStatus = 0; 
        setBackground(color[currentStatus]); 
      } 
    } 




    public void unselectCell() { 
      if(currentStatus == 1 || newStatus == 1) { 
        currentStatus = newStatus = 0; 
        setBackground(color[currentStatus]); 
      } 
    } 

    //If the mouse is in a cellHouse while being pressed, cell becomes alive 
    public void selectCells() { 
      if(mouseHold) { 
        currentStatus = newStatus = 1; 
        setBackground(color[1]); 
      } 
    } 

    //If the mouse is clicked on a cellHouse, cell comes to life 
    public void selectACell() { 
      mouseHold = true; 
      currentStatus = newStatus = 1; 
      setBackground(color[1]); 
    } 

    //Set mouse as not being held anymore 
    public void setMouseHold() { 
      mouseHold = false; 
    } 

} 

Programme sans MVC mise en œuvre

package lifepreparation; 

import java.awt.Color; 
import java.awt.*; 
import java.awt.event.*; 
import java.util.Hashtable; 
import javax.swing.*; 

public class LifeView extends JFrame implements ActionListener { 

    //Cell Color: cell[0] = dead cell, cell[1] = live cell. 
    private static final Color[] color = {Color.LIGHT_GRAY, Color.GREEN}; 

    //Size of cells 
    private static final int cellSize = 15; 
    private static final Dimension citySize = new Dimension(cellSize, cellSize); 

    //Label used to house cells 
    private LifeLabel[][] cellHouse; 

    //Timer used to fire the next generation 
    private Timer timer; 

    //Generation counter - used to count the number of generations 
    private int generationCount = 0; 
    private JLabel generationLabel = new JLabel("Generation: 0"); 


    //Declare default buttons 
    private JButton startB = new JButton("Start"); 
    private JButton pauseB = new JButton("Pause"); 
    private JButton clearB = new JButton("Clear"); 

    //Slider to adjust the time interval between generations 
    private static final int minSpeed = 0; 
    private static final int maxSpeed = 1000; 
    private static final int speedMajorTicks = (maxSpeed-minSpeed)/5; 
    private static final int speedMinorTicks = (maxSpeed-minSpeed)/20; 
    JSlider generationS = new JSlider(minSpeed,maxSpeed); 

    //Identifies game status: false=pause, true=running 
    private boolean runStatus = false; 

    // if the mouse is down or not 
    private boolean mouseHold = false; 

    public LifeView(int boardRow, int boardCol) { 
     super("Game Of Life"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     //**START Create labels to house cells, +2 more to calculate cells that are out of bounds 
     cellHouse = new LifeLabel[boardRow+2][boardCol+2]; 
     for(int r = 0; r < boardRow+2; r++) { 
      for(int c = 0; c < boardCol+2; c++) { 
       cellHouse[r][c] = new LifeLabel(); 
      } 
    } 
     //--END Create Labels 

     //Panel to hold cell houses 
     JPanel panel = new JPanel(new GridLayout(boardRow, boardCol, 1, 1)); 
     panel.setBackground(Color.BLACK); 
     panel.setBorder(BorderFactory.createLineBorder(Color.BLACK)); 

     //Add cellHouses to the panel 
     for(int r = 1; r < boardRow+1; r++) { 
       for(int c = 1; c < boardCol+1; c++) { 
         panel.add(cellHouse[r][c]); 
         cellHouse[r][c].addNeighbor(cellHouse[r-1][c]); //Add to TOP^
         cellHouse[r][c].addNeighbor(cellHouse[r+1][c]); //Add to BOTTOM _ 
         cellHouse[r][c].addNeighbor(cellHouse[r][c-1]); //Add to left <- 
         cellHouse[r][c].addNeighbor(cellHouse[r][c+1]); //Add to right -> 
         cellHouse[r][c].addNeighbor(cellHouse[r-1][c-1]); //Add to top left ^<- 
         cellHouse[r][c].addNeighbor(cellHouse[r-1][c+1]); //Add to top right ^-> 
         cellHouse[r][c].addNeighbor(cellHouse[r+1][c-1]); //Add to bottom left _<- 
         cellHouse[r][c].addNeighbor(cellHouse[r+1][c+1]); //Add to bottom right _-> 
       } 
     } 

     //Panel with cellHouses added to the container 
     add(panel, BorderLayout.CENTER); 

     //South Panel to hold buttons and widgets with extra features 
     JPanel panelBottom = new JPanel(); 

     //buttonPanel to hold start, pause, clear features 
     JPanel buttonPanel = new JPanel(); 
     clearB.addActionListener(this); 
     buttonPanel.add(clearB); 
     pauseB.addActionListener(this); 
     pauseB.setEnabled(false); 
     buttonPanel.add(pauseB); 
     startB.addActionListener(this); 
     buttonPanel.add(startB);    

     //speedPanel to hold slider to adjust the time interval 
     JPanel speedPanel = new JPanel(); 
     JLabel speedText = new JLabel("Set Speed:"); 
     generationS.setMajorTickSpacing(speedMajorTicks); 
     generationS.setMinorTickSpacing(speedMinorTicks); 
     generationS.setPaintTicks(true); 
     // the labels for the Slider 
     Hashtable<Integer, JLabel> speedLabel = new Hashtable<Integer, JLabel>(); 
     for(int i = 0; i <= maxSpeed; i++) { 
       speedLabel.put(new Integer(i * speedMajorTicks), new JLabel("" + i)); 
     } 
     generationS.setLabelTable(speedLabel); 
     generationS.setPaintLabels(true); 


     generationLabel.setHorizontalAlignment(SwingConstants.CENTER); 

     speedPanel.add(speedText); 
     speedPanel.add(generationS); 

     panelBottom.add(buttonPanel); 
     panelBottom.add(speedPanel); 
     panelBottom.add(generationLabel); 

     // add bottom panel to the JFrame 
     add(panelBottom, BorderLayout.SOUTH); 

     // put the frame on 
     setLocation(20, 20); 
     pack(); 
     setVisible(true); 
     // start the thread that run the cycles of life 
     timer = new Timer(maxSpeed - generationS.getValue(), this); 
    } 

    //Action to take dependent on the action referenced by the JButton and Timer 
    public void actionPerformed(ActionEvent e) { 
     //Get action reference 
     Object o = e.getSource(); 

       //Action reference is to clear 
     if(o == clearB) { 
      timer.stop(); //Stop the timer 
      runStatus = false; //Set game as not running 
      pauseB.setEnabled(false); //Disable the pause button 
      startB.setEnabled(true); //Enable the start button 
      //Remove/Clear all cells from the cellHouse 
      for(int r = 1; r < cellHouse.length -1; r++) { 
       for(int c = 1; c < cellHouse[r].length -1; c++) { 
        cellHouse[r][c].clear(); 
       } 
      } 
      //Reset the generation count 
      generationCount = 0; 
      generationLabel.setText("Generation: 0"); 
      return; 
     } 
     //Action reference is to pause 
     if(o == pauseB) { 
      timer.stop(); //Stop the timer 
      runStatus = false; //Set game as not running 
      pauseB.setEnabled(false); //Disable the pause button 
      startB.setEnabled(true); //Enable the start button 
      return; 
     } 
     //Action reference is to start 
     if(o == startB) { 
      pauseB.setEnabled(true); //Enable the pause button 
      startB.setEnabled(false); //Disable the start button 
      runStatus = true; //Set game as running 
      timer.setDelay(maxSpeed - generationS.getValue()); //Adjust the speed 
      timer.start(); 
      return; 
     } 

     //If the action is set by timer, set speed 
     timer.setDelay(maxSpeed - generationS.getValue()); 

     //If the game is not running, exit and do nothing more 
     if(!runStatus) return; 

       //Update generation count and display 
       ++generationCount; 
     generationLabel.setText("Generation: " + generationCount); 

       //Check to see if the cell should be buried 
     for(int r = 0; r < cellHouse.length; r++) { 
      for(int c = 0; c < cellHouse[r].length; c++) { 
       cellHouse[r][c].checkGeneration(); 
      } 
     } 

       //Update to the next generation 
     for(int r = 0; r < cellHouse.length; r++) { 
      for(int c = 0; c < cellHouse[r].length; c++) { 
       cellHouse[r][c].updateGeneration(); 
      } 
     } 
    } 
    //Run App 
    public static void main(String[] arg) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       new LifeView(30, 50); 
      } 
     }); 
    } 

    //LifeModel to handle cell life and death algorithm 
    class LifeLabel extends JLabel implements MouseListener { 
     private int currentGen, newGen; 
     private int nbNeighbor; 
     private LifeLabel[] Neighbor = new LifeLabel[8]; 

     LifeLabel() { 
      currentGen = newGen = 0; //Currently Dead 
      setOpaque(true); //Show color 
      setBackground(color[0]); //Light Gray color 
      addMouseListener(this); //Add mouseListener 
      this.setPreferredSize(citySize); //Set the dimension of the board 
     } 
     //Add a neighbor 
     void addNeighbor(LifeLabel n) { 
      Neighbor[nbNeighbor++] = n; 
     } 

     //Check to see if a cell should live or not 
     void checkGeneration() { 
      //Number of neighbors that are alive 
      int nbAlive = 0; 

      //Check the status of the neighbors 
      for(int i = 0; i < nbNeighbor; i++) 
       nbAlive += Neighbor[i].currentGen; 

         //If status of cell is alive 
      if(currentGen == 1) { 
           //Bury cell if it has less than two neighbors 
       if(nbAlive < 2) 
        newGen = 0; 
           //Bury cell if it has more than three live neighbors 
       if(nbAlive > 3)    
        newGen = 0; 
      } 
      else { 
           //Dead cells with three live neighbors get reborn 
       if(nbAlive == 3)    
        newGen = 1; 
      } 
     } 
     //Switch to next generation 
     void updateGeneration() { 
      if(currentGen != newGen) { //Adjust color for the new generation 
       currentGen = newGen; 
       setBackground(color[currentGen]); 
      } 
     } 

     //Bury all cells in the city 
     void clear() { 
      if(currentGen == 1 || newGen == 1) { 
       currentGen = newGen = 0; 
       setBackground(color[currentGen]); 
      } 
     } 

     public void mouseClicked(MouseEvent arg0) { 
         if(currentGen == 1 || newGen == 1) { 
       currentGen = newGen = 0; 
       setBackground(color[currentGen]); 
      } 
     } 

     //If the mouse is in a cellHouse while being pressed, cell becomes alive 
     public void mouseEntered(MouseEvent arg0) { 
      if(mouseHold) { 
       currentGen = newGen = 1; 
       setBackground(color[1]); 
      } 
     } 

     public void mouseExited(MouseEvent arg0) { 

     } 

     //If the mouse is clicked on a cellHouse, cell comes to life 
     public void mousePressed(MouseEvent arg0) { 
      mouseHold = true; 
      currentGen = newGen = 1; 
      setBackground(color[1]); 
     } 

     //Set mouse as not being held anymore 
     public void mouseReleased(MouseEvent arg0) { 
      mouseHold = false; 
     } 
    } 
} 
+2

MVC pour le jeu de la vie de Conway? On dirait que c'est trop. Tout ce dont vous avez vraiment besoin, c'est ↑ 1 ⍵∨.^3 4 = + /, ¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵': P ... mais sérieusement, attendez-vous vraiment des gens lire à travers votre (vos) mur (x) de code? Il vaut mieux découper autant de bits sans rapport/moins pertinents que possible. –

+0

Je suis tombé sur une implémentation de Game of Life qui est pleine de motifs design dans le livre "Holub on Patterns". Peut-être que vous serez intéressé. – Nowaker

+0

Est-ce que ce sont les devoirs? Si oui, veuillez le déclarer comme tel. – javamonkey79

Répondre

2

Votre code trop difficile à suivre, mais je l'ai fait une application à l'aide mvc en swing.

Mon conseil est d'avoir quelque chose comme ça dans une classe principale:

MainModel  model  = new MainModel(); 
    MainView  view  = new MainView(model); 
    MainController controller = new MainController(model, view); 

Votre commande est ok.

La vue semble correcte, mais vous devriez avoir des méthodes addActionListener séparées pour clearB, startB, pauseB (c'est peut-être le problème).

Le modèle est où le cerveau devrait être. Ne pas étendre JLabel, n'a pas de sens du tout.

Espérons que cela aide.