Как я могу установить эту программу, чтобы соответствовать шаблону проектирования MVC - PullRequest
0 голосов
/ 29 ноября 2010

Мне кажется, я получил большую часть MVC для этой программы - Game Of Life.Однако я не могу заставить MouseListener работать должным образом.Как я могу изменить это соответствие шаблону проектирования MVC?

Вид

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

}

Контроллер

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

Модель

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

}

Программа без реализации MVC

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

1 Ответ

2 голосов
/ 30 ноября 2010

Твоему коду слишком сложно следовать, но я сделал приложение, использующее mvc на качелях.

Мой совет - иметь что-то подобное в главном классе:

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

С вашим контроллером все в порядке.

Представление выглядит нормально, но у вас должны быть отдельные методы addActionListener для clearB, startB, pauseB (возможно, в этом проблема).

Модель - это место, где должен быть мозг,Не расширяйте JLabel, не имеет смысла вообще.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...