如何设置该程序以匹配 MVC 设计模式

发布于 2024-10-05 02:23:14 字数 23711 浏览 3 评论 0原文

我相信我已经掌握了这个程序 - Game Of Life 的大部分 MVC 部分。但是我无法让 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;
        }
    }
}

I believe I have got most of the MVC part down for this program - Game Of Life. However I can't get the MouseListener to work properly. How can I change this match the MVC design pattern?

View

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

}

Controller

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

Model

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

}

Program without MVC implementation

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤独陪着我 2024-10-12 02:23:14

你的代码太难理解了,但我已经在 swing 中使用 mvc 做了一个应用程序。

我的建议是在主类中有这样的东西:

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

你的控制器没问题。

该视图看起来不错,但您应该为clearB、startB、pauseB 提供单独的addActionListener 方法(也许这就是问题所在)。

模型就是大脑应该在的地方。不要扩展 JLabel,根本没有意义。

希望这有帮助。

Your code it too hard to follow, but I have done an application using mvc in swing.

My advice is to have something like this in a Main class:

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

Your controller is ok.

The view looks ok, but you should have separate addActionListener methods for clearB, startB, pauseB (perhaps that's the problem).

The model is where the brain should be. Do not extend JLabel, doesn't make sense at all.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文