I added listeners to my JButtons for the popup menu but when the popup menu appears the JButtons disappear and I would need to hover my cursor on the buttons to make them appear again. Why is it like this?
(all the methods here are in the same class)
public Inventory() {
setLayout(null);
setBounds(0, 0, 175, 210);
initPopupMenu(); // this just sets what is inside the popup menu
int x;
// 30 buttons
for(x = 0; x < 30; x++) {
button[x] = new JButton();
add(button[x]);
button[x].addMouseListener(this);
}
x = 0;
// it's a grid of buttons
for(int i = 0; i < 5; i++)
for(int j = 0; j < 6; j++) {
button[x].setBounds(i*35+1,j*35+1, 33,33);
x++;
}
}
public void mouseClicked(MouseEvent e) {
for(int j = 0; j < 30; j++) // i tried this one but it still disappears
button[j].repaint();
for(int i = 0; i < 30; i++) {
if(e.getSource() == button[i]) {
System.out.println("You pressed Button "+i);
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
}
This is what happens,
Stop using null Layout, seems like that can be one of the issues regarding this. Your JFrame appears sort of BLACK to me, is this some THEME or a new LOOK AND FEEL you are using, that can be the cause of this thing too. Here check this out, it's working flawlessly here with this code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonPopUp
{
private static final int SIZE = 30;
private JButton[] button = new JButton[SIZE];
private JPopupMenu popup = new JPopupMenu("Hello World");
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Button POP UP Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
final JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(0, 5));
JMenuItem menuItem1 = new JMenuItem("Menu Item 1");
JMenuItem menuItem2 = new JMenuItem("Menu Item 2");
//popup.add(greetings);
popup.insert(menuItem1, 0);
popup.insert(menuItem2, 1);
for (int i = 0; i < SIZE; i++)
{
button[i] = new JButton();
button[i].setBorder(BorderFactory.createEtchedBorder());
button[i].addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent me)
{
System.out.println("I am WORKING!!");
popup.show((JComponent)me.getSource(), me.getX(), me.getY());
}
});
contentPane.add(button[i]);
}
frame.getContentPane().add(contentPane);
frame.setSize(175, 250);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ButtonPopUp().createAndDisplayGUI();
}
});
}
}
Here is the output :
Related
I am new to java and am very confused about errors in my code. I have the error at line 48 "local variables referenced from an inner class must be final or effectively final". here is my code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MemoryGame extends JFrame
{
private JButton[][] buttons = new JButton[4][4];
private Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW};
private List<Color> colorList = new ArrayList<>();
private int score = 0;
public MemoryGame()
{
setTitle("Memory Game");
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(4, 4));
// populate colorList with two copies of each color
for (int i = 0; i < 2; i++)
{
for (Color color : colors)
{
colorList.add(color);
}
}
// shuffle colorList
Collections.shuffle(colorList);
int index = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
JButton button = new JButton();
button.setBackground(Color.GRAY);
buttons[i][j] = button;
add(button);
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
final int currentIndex = index;
JButton clickedButton = (JButton) e.getSource();
Color color = colorList.get(currentIndex);
clickedButton.setBackground(color);
clickedButton.setEnabled(false);
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 4; y++)
{
if (buttons[x][y].getBackground() == color && buttons[x][y] != clickedButton)
{
buttons[x][y].setEnabled(false);
score++;
if (score == 8)
{
JOptionPane.showMessageDialog(MemoryGame.this, "You won!");
System.exit(0);
}
}
}
}
}
});
index++;
}
}
setVisible(true);
}
public static void main(String[] args)
{
new MemoryGame();
}
}
I've tried different things to solve the error and they just result in more errors. the program is meant to have a grid of different squares that can be clicked on to display their colors and matched by the user. when the user matches all of the colors on the grid they win.
The problem is with final int currentIndex = index; as the compiler was telling you in the error message. actionPerformed will run at some unspecified future time and the compiler has no idea what value of index you expect to find there at that time.
What do you want to do? Assign colors to buttons. You can do that more directly with
JButton button = new JButton();
button.setBackground(Color.GRAY);
buttons[i][j] = button;
// let's store the color for later
button.putClientProperty("color", colorList.get(index));
add(button);
outside the handler.
And then retrieving it inside:
public void actionPerformed(ActionEvent e)
{
JButton clickedButton = (JButton) e.getSource();
Color color = (Color)clickedButton.getClientProperty("color");
I am trying to make a method that disables JButtons.
The JButtons are in an array in the form of a grid, JButton [int][int] and the integers are supposed to be coordinates.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;
public class BS {
public static JFrame f = new JFrame("BS");
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
initializeGui();
}
});
}
static void initializeGui() {
JPanel gui = new JPanel(new BorderLayout(3,1));
//This is the array of the JButtons in the form of a grid
final JButton[][] coordinates = new JButton[15][15];
JPanel field;
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
field = new JPanel(new GridLayout(0, 15));
field.setBorder(new CompoundBorder(new EmptyBorder(15,15,15,15),new LineBorder(Color.BLACK)));
JPanel boardConstrain = new JPanel(new GridBagLayout());
boardConstrain.add(field);
gui.add(boardConstrain);
//The making of the grid
for (int ii = 0; ii < coordinates.length; ii++) {
for (int jj = 0; jj < coordinates[ii].length; jj++) {
JButton b = new JButton();
ImageIcon icon = new ImageIcon(
new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB));
b.setIcon(icon);
coordinates[jj][ii] = b;
field.add(coordinates[jj][ii]);
}
}
f.add(gui);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
}
I did some changes in your code:
public static JFrame f = new JFrame("BS"); JFrame shouldn't be static and should have a more meaningful name (like frame for example).
final JButton[][] coordinates = new JButton[15][15]; moved this array as a class member and made it non final and also changed the name to buttons as it's easier to know what it is (coordinates to me, sounds more like an array of Point or int)
After that I added an ActionListener, see How to use Actions tutorial.
private ActionListener listener = e -> {
//Loops through the whole array in both dimensions
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (e.getSource().equals(buttons[i][j])) { //Find the JButton that was clicked
if (isStartButton) { //startButton is a boolean variable that tells us if this is the first button clicked or not
startXCoord = i;
startYCoord = j;
} else {
endXCoord = i;
endYCoord = j;
disableButtons(); //Only when we have clicked twice we disable all the buttons in between
}
isStartButton = !isStartButton; //In every button click we change the value of this variable
break; //No need to keep looking if we found our clicked button. Add another one with a condition to skip the outer loop.
}
}
}
};
And a method called disableButtons() which disables all the buttons between the 2 clicked buttons:
private void disableButtons() {
compareCoords(); //This method checks if first button clicked is after 2nd one.
for (int i = startXCoord; i <= endXCoord; i++) {
for (int j = startYCoord; j <= endYCoord; j++) {
buttons[i][j].setEnabled(false); //We disable all buttons in between
}
}
}
At the end our code ends like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
public class DisableButtonsInBetween {
private JFrame frame = new JFrame(getClass().getSimpleName());
private JButton[][] buttons;
private int startXCoord = -1;
private int startYCoord = -1;
private int endXCoord = -1;
private int endYCoord = -1;
private boolean isStartButton = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DisableButtonsInBetween().initializeGui();
}
});
}
void initializeGui() {
JPanel gui = new JPanel(new BorderLayout(3, 1));
// This is the array of the JButtons in the form of a grid
JPanel pane;
buttons = new JButton[15][15];
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
pane = new JPanel(new GridLayout(0, 15));
pane.setBorder(new CompoundBorder(new EmptyBorder(15, 15, 15, 15), new LineBorder(Color.BLACK)));
JPanel boardConstrain = new JPanel(new GridBagLayout());
boardConstrain.add(pane);
gui.add(boardConstrain);
// The making of the grid
for (int ii = 0; ii < buttons.length; ii++) {
for (int jj = 0; jj < buttons[ii].length; jj++) {
buttons[jj][ii] = new JButton();
ImageIcon icon = new ImageIcon(new BufferedImage(30, 30, BufferedImage.TYPE_INT_ARGB));
buttons[jj][ii].setIcon(icon);
buttons[jj][ii].addActionListener(listener);
pane.add(buttons[jj][ii]);
}
}
frame.add(gui);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setMinimumSize(frame.getSize());
frame.setVisible(true);
}
//The ActionListener is what gets called when you click a JButton
private ActionListener listener = e -> {
//These for loops are done to identify which button was clicked.
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (e.getSource().equals(buttons[i][j])) {
if (isStartButton) {
//We save the coords of the 1st button clicked
startXCoord = i;
startYCoord = j;
} else {
//We save the coords of the 2nd button clicked and call the disableButtons method
endXCoord = i;
endYCoord = j;
disableButtons();
}
isStartButton = !isStartButton;
break;
}
}
}
};
//This method disables all the buttons between the 2 that were clicked
private void disableButtons() {
compareCoords();
for (int i = startXCoord; i <= endXCoord; i++) {
for (int j = startYCoord; j <= endYCoord; j++) {
buttons[i][j].setEnabled(false);
}
}
}
//This method compares the coords if the 2nd button was before (in its coords) than the 1st one it switched their coords
private void compareCoords() {
if (endXCoord < startXCoord) {
int aux = startXCoord;
startXCoord = endXCoord;
endXCoord = aux;
}
if (endYCoord < startYCoord) {
int aux = startYCoord;
startYCoord = endYCoord;
endYCoord = aux;
}
}
}
I hope this is what you were trying to do... if not please clarify.
I do not have the arrow operator, " -> ". I think it requires a higher Java. Is there a way to replace this?
For Java 7 and lower use this for the ActionListener:
private ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < buttons.length; i++) {
for (int j = 0; j < buttons[i].length; j++) {
if (e.getSource().equals(buttons[i][j])) {
if (isStartButton) {
startXCoord = i;
startYCoord = j;
} else {
endXCoord = i;
endYCoord = j;
disableButtons();
}
isStartButton = !isStartButton;
break;
}
}
}
}
};
In my Springbreak holiday I started to write Checkers Game. I have created my CheckersBoard but I couldn't write MouseListener part. Can you help me with this part? I'm not pretty sure how to implement this part? Is MouseListener correct? Or should I choose another Listener? I have googled but couldn't any clue.
Thank you so much.
public class CheckersGUI {
private final JPanel gui = new JPanel(new BorderLayout(3, 3));
private JButton[][] Squares = new JButton[8][8];
private JPanel Board;
private final JLabel message = new JLabel(
"Ready to play!");
private static final String COLS = "ABCDEFGH";
private ImageIcon brown = new ImageIcon("brown.jpg");
private ImageIcon red = new ImageIcon("red.png");
CheckersGUI() {
create();
//create ButtonHandler
/* ButtonHandler handler = new ButtonHandler();
for (int i=0; i<Squares.length; i++){
for (int j=0; i<Squares[0].length; i++){
Squares[i][j].addMouseListener(handler);
}
}
}
private class ButtonHandler implements MouseListener{
public void MouseClicked ( MouseEvent event){
}*/
}
public final void create() {
// set up the main GUI
gui.setBorder(new EmptyBorder(5, 5, 5, 5));
JToolBar tools = new JToolBar();
tools.setFloatable(false);
gui.add(tools, BorderLayout.PAGE_START);
Action newGameAction = new AbstractAction("New") {
#Override
public void actionPerformed(ActionEvent e) {
setupNewGame();
}
};
tools.add(newGameAction);
// TODO - add functionality!
tools.addSeparator();
tools.add(message);
gui.add(new JLabel(""), BorderLayout.LINE_START);
Board = new JPanel(new GridLayout(0, 9)) ;
Board.setBorder(new CompoundBorder(
new EmptyBorder(8,8,8,8),
new LineBorder(Color.BLACK)
));
JPanel boardConstrain = new JPanel(new GridBagLayout());
boardConstrain.add(Board);
gui.add(boardConstrain);
// create the chess board squares
Insets buttonMargin = new Insets(0, 0, 0, 0);
for (int ii = 0; ii < Squares.length; ii++) {
for (int jj = 0; jj < Squares[ii].length; jj++) {
JButton b = new JButton();
b.setMargin(buttonMargin);
ImageIcon icon = new ImageIcon(
new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB));
b.setIcon(icon);
if ((jj % 2 == 1 && ii % 2 == 1)
|| (jj % 2 == 0 && ii % 2 == 0)) {
b.setBackground(Color.WHITE);
} else {
b.setBackground(Color.BLACK);
}
Squares[jj][ii] = b;
}
}
/*
* fill the chess board
*/
Board.add(new JLabel(""));
// fill the top row
for (int ii = 0; ii < 8; ii++) {
Board.add(
new JLabel(COLS.substring(ii, ii + 1),
SwingConstants.CENTER));
}
// fill the black non-pawn piece row
for (int ii = 0; ii < 8; ii++) {
for (int jj = 0; jj < 8; jj++) {
switch (jj) {
case 0:
Board.add(new JLabel("" + (9-(ii + 1)),
SwingConstants.CENTER));
default:
Board.add(Squares[jj][ii]);
}
}
}
}
public final JComponent getGui() {
return gui;
}
/**
* Initializes the icons of the initial chess board piece places
*/
private final void setupNewGame() {
message.setText("Make your move!");
for (int ii = 0; ii < 8; ii++) {
Squares[ii][1].setIcon(red);
}
for (int ii = 0; ii < 8; ii++) {
Squares[ii][2].setIcon(red);
}
for (int ii = 0; ii < 8; ii++) {
Squares[ii][5].setIcon(brown);
}
for (int ii = 0; ii < 8; ii++) {
Squares[ii][6].setIcon(brown);
}
}
public static void main(String[] args) {
CheckersGUI cg = new CheckersGUI();
JFrame f = new JFrame("Checkers");
f.add(cg.getGui());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
f.setResizable(false);
f.setVisible(true);
}
}
You can add an ActionListener to each button. If the button is pressed (actually, when it is released) the actionPerformed method will be called.
Add the following to your code, to make each square red after it has been clicked:
public static class ButtonHandler implements ActionListener {
private JButton b;
public ButtonHandler(JButton b) {
this.b = b;
}
#Override
public void actionPerformed(ActionEvent e) {
b.setBackground(Color.red);
}
}
This is the handler. Notice that each handler instance will be associated with a button.
Now, create and add a new ButtonHandler to each button after it has been created:
JButton b = new JButton();
...
b.addActionListener(new ButtonHandler(b));
You can change the implementation of actionPerformed.
Example: Add a method getCurrentPlayer() to actionPerformed, then, if the current player is player one, change the color to blue, else, change the color to red.
I trust this will help you to achieve what you need.
i want to overlap image on button(when it is clicked)....but on clicking it is not overlapping....please guide me where i am wrong....is it not possible to do so???
i am using frame to add buttons....
import java.awt.*;
import java.awt.event.*;
public class d extends Frame implements ActionListener {
Image img, i1, i2;
int x, y;
String msg;
Button one, two;
d() {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setSize(1000, 500);
setVisible(true);
setLayout(null);
one = new Button("1");
two = new Button("2");
add(one);
add(two);
one.addActionListener(this);
two.addActionListener(this);
one.setBounds(200, 100, 100, 100);
two.setBounds(300, 100, 100, 100);
}
public void actionPerformed(ActionEvent e) {
msg = e.getActionCommand();
if (msg.equals("1")) {
msg = "Pressed 1";
img = i1;
x = 200;
y = 100;
} else {
msg = "Pressed 2";
img = i2;
x = 300;
y = 100;
}
repaint();
}
public void paint(Graphics g) {
Toolkit tool = Toolkit.getDefaultToolkit();
i1 = tool.getImage("F:/Memories/rawk garden/a.jpg");
i2 = tool.getImage("F:/Memories/rawk garden/b.jpg");
g.drawImage(img, x, y, 100, 100, this);
g.drawString(msg, 100, 300);
}
public static void main(String s[]) {
new d();
}
}
I have already shared you code for this in your last post where I suggested you some points with the sample code to achieve it using JLabel.
Read more points...
Don't use null layout. There are lots of Layout Managers choose any one that suits as per your application design.
How to Use Various Layout Managers
From comments below:
actually I am making minesweeper type game...i want button to change into image and once one button is converted to image...that image remains there.
Use JButton#setIcon() method to set the icon of the button.
Here is the sample code where
I have created a 9x9 grid that contains buttons.
Each cell has a random boolean flag whether it has mine or not.
When button is clicked I am setting its icon if it has mine.
Simply set the text empty and make it disabled to stop further clicks on already clicked button.
sample code:
final Image mine = ImageIO.read(new File("resources/mine.png"));
final boolean[][] showMine = new boolean[9][9];
Random random = new Random();
JPanel panel = new JPanel(new GridLayout(9, 9));
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
showMine[i][j] = random.nextBoolean();
final int x = i;
final int y = j;
final JButton button = new JButton();
button.setText(String.valueOf(i * 9 + j));
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
button.setText("");
if (showMine[x][y]) {
button.setDisabledIcon(new ImageIcon(mine));
}
}
});
panel.add(button);
}
}
add(panel);
snapshot:
Setting an image on a button can be done as follows:
Button myButton = new Button(new ImageIcon("image_path"));
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;
}
}
}
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.