JavaFX memory game (trouble hiding the values of the tiles) - java

I'm making a memory game for school and I'm having a bit of trouble hiding the tiles in my gridpane.
I've got a seperate class where I use my eventhandlers.
I used an ObservableList to fill in my gridpane with tiles but I got no idea how to make them disappear. Thanks for taking a look , I tried to use a FadeTransition in the view class.
View
public class GameView extends GridPane {
private static final int PAREN = 10;
private Label scoreSpeler1;
private Label countDown;
private Label title;
private final static Color backgroundColor = Color.rgb(225, 93, 68);
int waarde = 0;
ObservableList<Button> vakken;
public GameView() {
this.initialiseNodes();
this.layoutNodes();
this.verdwijnWaarde();
this.toonWaarde();
}
private void initialiseNodes() {
scoreSpeler1 = new Label("Score: 0");
countDown = new Label("Tijd: 60");
title = new Label("Memory");
/*knoppen met cijfers*/
vakken = FXCollections.observableArrayList(new ArrayList<>());
for (int i = 0; i < PAREN; i++) {
vakken.add(new Button(String.valueOf(waarde)));
vakken.add(new Button(String.valueOf(waarde)));
waarde++;
}
FXCollections.shuffle(vakken);
}
private void layoutNodes() {
//score en tijd plaatsen
this.add(scoreSpeler1, 0, 0);
this.add(title, 2, 0);
this.add(countDown, 4, 0);
//memory knoppen plaatsen
int k = 0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 4; j++) {
this.add(vakken.get(k), i, j + 2);
k++;
}
}
//label uiterlijk
GridPane.setHalignment(countDown, HPos.RIGHT);
GridPane.setHalignment(title, HPos.CENTER);
title.setId("titelGame");
scoreSpeler1.setId("scoreSpeler1");
countDown.setId("countDown");
//button/memory uiterlijk
for (Button button : vakken) {
button.setPrefHeight(120);
button.setPrefWidth(90);
}
//gridpane uiterlijk
this.setGridLinesVisible(false);
this.setBackground(new Background(new BackgroundFill(backgroundColor, null, null)));
this.setHgap(15);
this.setVgap(15);
this.setPadding(new Insets(10, 10, 10, 10));
this.autosize();
this.setAlignment(Pos.CENTER);
}
public void verdwijnWaarde() {
FadeTransition verstopWaardes = new FadeTransition();
verstopWaardes.durationProperty(Duration.seconds(2), this.vakken.get(1));
verstopWaardes.setToValue(0);
verstopWaardes.play();
}
public void toonWaarde() {
FadeTransition toonWaardes = new FadeTransition();
toonWaardes.durationProperty(Duration.seconds(0.5), vakken);
toonWaardes.setToValue(1);
toonWaardes.play();
}
}
presenter
public class GamePresenter {
private MemoryModel model;
private GameView gameView;
public GamePresenter(MemoryModel model, GameView gameView){
this.model = model;
this.gameView = gameView;
addEventHandlers();
}
private void addEventHandlers(){
gameView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
gameView.toonWaarde();
}
});
}
private void updateView(){
}
public void addWindowEventHandlers(){
}
}

Related

How to have a MotionListener called on a JPanel that is covered

This question is to help me solve my other question. I have a JPanel that is completely covered by JLabels. I have added a MotionListener to the panel but it is never called since the labels are in the way. If I remove the labels my MotionnListener is called properly.
Is there a way I can have the covered panel see the motion events?
public class ChangesAttempt extends JPanel {
private static final long serialVersionUID = -8031881678612431401L;
static JFrame frame;
static JPanel grid;
static JLabel[][] squares;
static boolean[][] litSquares;
static int size, boardSize;
MouseEvent listener = new MouseEvent();
MotionListener mListerner = new MotionListener();
Color backGround = Color.BLUE;
Color selected = Color.PINK;
public ChangesAttempt(int size) {
ChangesAttempt.size = size;
squares = new JLabel[size][size];
litSquares = new boolean[size][size];
grid = new JPanel(new GridLayout(size, size));
grid.addMouseMotionListener(mListerner);
/*Coment out setBoard(); below to see the mousedDragged method actually being called
since the JLabels will not be in the way.*/
setBoard();
frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.add(grid, BorderLayout.CENTER);
frame.setTitle("ChangedLife");
if (25 * size < 525)
boardSize = 525;
else
boardSize = 25 * size;
frame.setSize(boardSize, boardSize);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
class MouseEvent implements MouseListener {
#Override
public void mousePressed(java.awt.event.MouseEvent e) {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (e.getSource() == squares[i][j]) {
if (litSquares[i][j] == false) {
squares[i][j].setBackground(selected);
litSquares[i][j] = true;
} else {
squares[i][j].setBackground(backGround);
litSquares[i][j] = false;
}
}
}
}
}
#Override
public void mouseClicked(java.awt.event.MouseEvent e) {
}
#Override
public void mouseEntered(java.awt.event.MouseEvent e) {
}
#Override
public void mouseExited(java.awt.event.MouseEvent e) {
}
#Override
public void mouseReleased(java.awt.event.MouseEvent e) {
}
}
class MotionListener implements MouseMotionListener {
#Override
public void mouseDragged(java.awt.event.MouseEvent e) {
Point p = e.getPoint();
System.out.println("mouse Dragged to " + p);
}
#Override
public void mouseMoved(java.awt.event.MouseEvent e) {
// TODO Auto-generated method stub
}
}
public void setBoard() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
squares[i][j] = new JLabel();
squares[i][j].addMouseListener(listener);
squares[i][j].setOpaque(true);
squares[i][j].setBackground(backGround);
grid.add(squares[i][j]);
}
}
}
class MyLabel extends JLabel {
private static final long serialVersionUID = -1414933339546989142L;
}
public static void main(String args[]) {
new ChangesAttempt(20);
}
}
There's no "easy" way to achieve this, it might be better to move all you mouse listeners to the panel instead.
This would require you to look up the component (that's within the parent component) at the specified click point, for example...
#Override
public void mousePressed(java.awt.event.MouseEvent e) {
Component component = e.getComponent();
Component source = component.getComponentAt(e.getPoint());
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (source == squares[i][j]) {
if (litSquares[i][j] == false) {
squares[i][j].setBackground(selected);
litSquares[i][j] = true;
} else {
squares[i][j].setBackground(backGround);
litSquares[i][j] = false;
}
}
}
}
}
This will work, if you remove the MouseListener from the labels and instead, add it to the grid, allowing with your MouseMotionListener

java swing setlocation doesn't work for second time

Frame has mainContentPane with layout manager = null
mainContentPane gamePanel, which holds jLabel Background at z-order 1 and a bunch of backgammon stones at z- order 0, if i set their positions before adding them to game panel, they end up in places i need them to be, but if im trying to set their places in game they all end ap at point 0,0 and calling get location says that its at a different location. Plese help me out on what im doing wrong with swing layout etc. setStones is the void that suppose to do it and getLocation after it ran gives locations I need, but everything is still at 0,0 on the screen
public class MainWindow extends JFrame implements ActionListener, ItemListener,
MouseListener, MouseMotionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private final int NUMBER_OF_STONES = 30;
private JPanel mainContentPane;
private JLayeredPane gamePanel;
private JLabel background;
private JMenuBar menuBar;
private JMenu menuGameTitle, aboutGameTitle;
private JMenuItem newGame, exit, help;
private JLabel[] stones;
private Dimension preferredSize;
private int stoneDragged = NUMBER_OF_STONES;
private int clickX = 0;
private int clickY = 0;
private HashMap<game.Color, String> stoneImage;
private HashMap<Integer, int[]> locations;
private int currStone;
public MainWindow() {
createGUI();
stoneImage = new HashMap<game.Color, String>();
stoneImage.put(game.Color.BLACK, "SilverNSH.jpg");
stoneImage.put(game.Color.WHITE, "GoldNSH.jpg");
locations = new HashMap<Integer, int[]>();
locations.put(0, new int[] {355,509});
locations.put(1, new int[] {655, 509});
.....
currStone = 0;
play();
}
private void createGUI() {
preferredSize = new Dimension(800, 600);
mainContentPane = new JPanel();
mainContentPane.setLayout(null);
mainContentPane.setPreferredSize(preferredSize);
gamePanel = new JLayeredPane();
gamePanel.setBounds(0, 0, 800, 600);
setSize(preferredSize);
background = new JLabel(new ImageIcon("BackGammon.jpg"));
// adding stones;
initStones();
for (int i = 0; i < stones.length; i++) {
gamePanel.add(stones[i], 0);
}
// setting background to 1 Z order
gamePanel.add(background, 1);
// set Z level to 0
for (int i = 0; i < stones.length; i++) {
gamePanel.setComponentZOrder(stones[i], 0);
}
mainContentPane.add(gamePanel);
setContentPane(mainContentPane);
pack();
}
private void initStones() {
stones = new JLabel[NUMBER_OF_STONES];
for (int i = 0; i < stones.length; i++) {
if (i < NUMBER_OF_STONES / 2) {
stones[i] = new JLabel(new ImageIcon("SilverNSH.gif"));
} else {
stones[i] = new JLabel(new ImageIcon("GoldNSH.gif"));
}
stones[i].setName(i + "");
stones[i].setSize(40,40);
stones[i].addMouseListener(this);
stones[i].addMouseMotionListener(this);
}
}
#Override
public void mousePressed(MouseEvent e) {
stoneDragged = Integer.parseInt(e.getComponent().getName());
clickX = e.getX();
clickY = e.getY();
}
#Override
public void mouseReleased(MouseEvent e) {
// no stone is dragged
stoneDragged = NUMBER_OF_STONES;
}
#Override
public void mouseDragged(MouseEvent e) {
// off screen check
int yLoc;
int xLoc;
if (stoneDragged >= 0 && stoneDragged < NUMBER_OF_STONES) {
xLoc = e.getComponent().getX() + e.getX() - clickX;
yLoc = e.getComponent().getY() + e.getY() - clickY;
stones[stoneDragged].setLocation(xLoc, yLoc);
if (stones[stoneDragged].getX() <= 50)
stones[stoneDragged].setLocation(51, 51);
if (stones[stoneDragged].getY() <= 50)
stones[stoneDragged].setLocation(51, 51);
if (stones[stoneDragged].getX() >= 660)
stones[stoneDragged].setLocation(659, 509);
if (stones[stoneDragged].getY() >= 510)
stones[stoneDragged].setLocation(659, 509);
}
}
private void play() {
setStones(board.getAmountArray(), board.getColorArray());
}
private void setStones(int[] amountArray, game.Color[] colorArray) {
currStone = 0;
for (int i = 0; i < Board.NO_OF_PLAYABLE_FIELDS;i++){
if (amountArray[i] != 0) {
placeStones(i, amountArray[i], stoneImage.get(colorArray[i]));
}
}
}
private void placeStones(int startPos, int amount, String picture) {
for (int i = 0; i < amount;i++){
stones[currStone].setIcon(new ImageIcon(picture));;
if (startPos < 13) {
stones[currStone].setLocation(locations.get(startPos)[0], locations.get(startPos)[1] - i*40);
} else {
stones[currStone].setLocation(locations.get(startPos)[0], locations.get(startPos)[1] + i*40);
}
stones[currStone].setSize(40, 40);
currStone++;
}
}
}

Fixing method latency in Java

Another problem, same program:
The following is MainGUI.java
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class MainGUI extends JFrame implements ActionListener
{
private static final long serialVersionUID = 4149825008429377286L;
private final double version = 8;
public static int rows;
public static int columns;
private int totalCells;
private MainCell[] cell;
public static Color userColor;
JTextField speed = new JTextField("250");
Timer timer = new Timer(250,this);
String generationText = "Generation: 0";
JLabel generationLabel = new JLabel(generationText);
int generation = 0;
public MainGUI(String title, int r, int c)
{
rows = r;
columns = c;
totalCells = r*c;
System.out.println(totalCells);
cell = new MainCell[totalCells];
setTitle(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Timer set up
timer.setInitialDelay(Integer.parseInt(speed.getText()));
timer.setActionCommand("timer");
//set up menu bar
JMenuBar menuBar = new JMenuBar();
JMenu optionsMenu = new JMenu("Options");
JMenu aboutMenu = new JMenu("About");
menuBar.add(optionsMenu);
menuBar.add(aboutMenu);
JMenuItem helpButton = new JMenuItem("Help!");
helpButton.addActionListener(this);
helpButton.setActionCommand("help");
aboutMenu.add(helpButton);
JMenuItem aboutButton = new JMenuItem("About");
aboutButton.addActionListener(this);
aboutButton.setActionCommand("about");
aboutMenu.add(aboutButton);
JMenuItem colorSelect = new JMenuItem("Select a Custom Color");
colorSelect.addActionListener(this);
colorSelect.setActionCommand("colorSelect");
optionsMenu.add(colorSelect);
JMenuItem sizeChooser = new JMenuItem("Define a Custom Size");
sizeChooser.addActionListener(this);
sizeChooser.setActionCommand("sizeChooser");
optionsMenu.add(sizeChooser);
//Create text field to adjust speed and its label
JPanel speedContainer = new JPanel();
JLabel speedLabel = new JLabel("Enter the speed of a life cycle (in ms):");
speedContainer.add(speedLabel);
speedContainer.add(speed);
speedContainer.add(generationLabel);
Dimension speedDim = new Dimension(100,25);
speed.setPreferredSize(speedDim);
//Create various buttons
JPanel buttonContainer = new JPanel();
JButton randomizerButton = new JButton("Randomize");
randomizerButton.addActionListener(this);
randomizerButton.setActionCommand("randomize");
buttonContainer.add(randomizerButton);
JButton nextButton = new JButton("Next"); //forces a cycle to occur
nextButton.addActionListener(this);
nextButton.setActionCommand("check");
buttonContainer.add(nextButton);
JButton startButton = new JButton("Start");
startButton.addActionListener(this);
startButton.setActionCommand("start");
buttonContainer.add(startButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(this);
stopButton.setActionCommand("stop");
buttonContainer.add(stopButton);
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(this);
clearButton.setActionCommand("clear");
buttonContainer.add(clearButton);
//holds the speed container and button container, keeps it neat
JPanel functionContainer = new JPanel();
BoxLayout functionLayout = new BoxLayout(functionContainer, BoxLayout.PAGE_AXIS);
functionContainer.setLayout(functionLayout);
functionContainer.add(speedContainer);
speedContainer.setAlignmentX(CENTER_ALIGNMENT);
functionContainer.add(buttonContainer);
buttonContainer.setAlignmentX(CENTER_ALIGNMENT);
//finish up with the cell container
GridLayout cellLayout = new GridLayout(rows,columns);
JPanel cellContainer = new JPanel(cellLayout);
cellContainer.setBackground(Color.black);
int posX = 0;
int posY = 0;
for(int i=0;i<totalCells;i++)
{
MainCell childCell = new MainCell();
cell[i] = childCell;
childCell.setName(String.valueOf(i));
childCell.setPosX(posX);
posX++;
childCell.setPosY(posY);
if(posX==columns)
{
posX = 0;
posY++;
}
cellContainer.add(childCell);
childCell.deactivate();
Graphics g = childCell.getGraphics();
childCell.paint(g);
}
//make a default color
userColor = Color.yellow;
//change icon
URL imgURL = getClass().getResource("images/gol.gif");
ImageIcon icon = new ImageIcon(imgURL);
System.out.println(icon);
setIconImage(icon.getImage());
//add it all up and pack
JPanel container = new JPanel();
BoxLayout containerLayout = new BoxLayout(container, BoxLayout.PAGE_AXIS);
container.setLayout(containerLayout);
container.add(cellContainer);
container.add(functionContainer);
add(menuBar);
setJMenuBar(menuBar);
add(container);
pack();
}
private void checkCells()
{
//perform check for every cell
for(int i=0;i<totalCells;i++)
{
cell[i].setNeighbors(checkNeighbors(i));
}
//use value from check to determine life
for(int i=0;i<totalCells;i++)
{
int neighbors = cell[i].getNeighbors();
if(cell[i].isActivated())
{
System.out.println(cell[i].getName()+" "+neighbors);
if(neighbors==0||neighbors==1||neighbors>3)
{
cell[i].deactivate();
}
}
if(cell[i].isActivated()==false)
{
if(neighbors==3)
{
cell[i].activate();
}
}
}
}
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("randomize"))
{
Random rn = new Random();
for(int i=0;i<totalCells;i++)
{
cell[i].deactivate();
if(rn.nextInt(6)==0)
{
cell[i].activate();
}
}
}
//help button, self-explanatory
if(e.getActionCommand().equals("help"))
{
JOptionPane.showMessageDialog(this, "The game is governed by four rules:\nFor a space that is 'populated':"
+ "\n Each cell with one or no neighbors dies, as if by loneliness."
+ "\n Each cell with four or more neighbors dies, as if by overpopulation."
+ "\n Each cell with two or three neighbors survives."
+ "\nFor a space that is 'empty' or 'unpopulated':"
+ "\n Each cell with three neighbors becomes populated."
+ "\nLeft click populates cells. Right click depopulates cells.","Rules:",JOptionPane.PLAIN_MESSAGE);
}
//shameless self promotion
if(e.getActionCommand().equals("about"))
{
JOptionPane.showMessageDialog(this, "Game made and owned by *****!"
+ "\nFree usage as see fit, but give credit where credit is due!\nVERSION: "+version,"About:",JOptionPane.PLAIN_MESSAGE);
}
//clears all the cells
if(e.getActionCommand().equals("clear"))
{
timer.stop();
generation = 0;
generationText = "Generation: "+generation;
generationLabel.setText(generationText);
for(int i=0;i<totalCells;i++)
{
cell[i].deactivate();
}
}
//starts timer
if(e.getActionCommand().equals("start"))
{
if(Integer.parseInt(speed.getText())>0)
{
timer.setDelay(Integer.parseInt(speed.getText()));
timer.restart();
}
else
{
JOptionPane.showMessageDialog(this, "Please use a value greater than 0!","Rules:",JOptionPane.ERROR_MESSAGE);
}
}
//stops timer
if(e.getActionCommand().equals("stop"))
{
timer.stop();
}
//run when timer
if(e.getActionCommand().equals("timer"))
{
generation++;
generationText = "Generation: "+generation;
generationLabel.setText(generationText);
timer.stop();
checkCells();
timer.setInitialDelay(Integer.parseInt(speed.getText()));
timer.restart();
}
//see checkCells()
if(e.getActionCommand().equals("check"))
{
generation++;
generationText = "Generation: "+generation;
generationLabel.setText(generationText);
checkCells();
}
//color select gui
if(e.getActionCommand().equals("colorSelect"))
{
userColor = JColorChooser.showDialog(this, "Choose a color:", userColor);
if(userColor==null)
{
userColor = Color.yellow;
}
}
//size chooser!
if(e.getActionCommand().equals("sizeChooser"))
{
SizeChooser size = new SizeChooser();
size.setLocationRelativeTo(null);
size.setVisible(true);
}
}
private int checkNeighbors(int c)
{
//if a LIVE neighbor is found, add one
int neighbors = 0;
if(cell[c].getPosX()!=0&&cell[c].getPosY()!=0)
{
if(c-columns-1>=0)
{
if(cell[c-columns-1].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c-columns-1].getName());
neighbors++;
}
}
}
if(cell[c].getPosY()!=0)
{
if(c-columns>=0)
{
if(cell[c-columns].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c-columns].getName());
neighbors++;
}
}
}
if(cell[c].getPosX()!=columns-1&&cell[c].getPosY()!=0)
{
if(c-columns+1>=0)
{
if(cell[c-columns+1].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c-columns+1].getName());
neighbors++;
}
}
}
if(cell[c].getPosX()!=0)
{
if(c-1>=0)
{
if(cell[c-1].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c-1].getName());
neighbors++;
}
}
}
if(cell[c].getPosX()!=columns-1)
{
if(c+1<totalCells)
{
if(cell[c+1].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c+1].getName());
neighbors++;
}
}
}
if(cell[c].getPosX()!=0&&cell[c].getPosY()!=rows-1)
{
if(c+columns-1<totalCells)
{
if(cell[c+columns-1].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c+columns-1].getName());
neighbors++;
}
}
}
if(cell[c].getPosY()!=rows-1&&cell[c].getPosY()!=rows-1)
{
if(c+columns<totalCells)
{
if(cell[c+columns].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c+columns].getName());
neighbors++;
}
}
}
if(cell[c].getPosX()!=columns-1&&cell[c].getPosY()!=rows-1)
{
if(c+columns+1<totalCells)
{
if(cell[c+columns+1].isActivated())
{
System.out.println(cell[c].getName()+" found "+cell[c+columns+1].getName());
neighbors++;
}
}
}
return neighbors;
}
}
The following is MainCell.java:
public class MainCell extends JPanel implements MouseListener
{
//everything here should be self-explanatory
private static final long serialVersionUID = 1761933778208900172L;
private boolean activated = false;
public static boolean leftMousePressed;
public static boolean rightMousePressed;
private int posX = 0;
private int posY = 0;
private int neighbors = 0;
private URL cellImgURL_1 = getClass().getResource("images/cellImage_1.gif");
private ImageIcon cellImageIcon_1 = new ImageIcon(cellImgURL_1);
private Image cellImage_1 = cellImageIcon_1.getImage();
private URL cellImgURL_2 = getClass().getResource("images/cellImage_2.gif");
private ImageIcon cellImageIcon_2 = new ImageIcon(cellImgURL_2);
private Image cellImage_2 = cellImageIcon_2.getImage();
private URL cellImgURL_3 = getClass().getResource("images/cellImage_3.gif");
private ImageIcon cellImageIcon_3 = new ImageIcon(cellImgURL_3);
private Image cellImage_3 = cellImageIcon_3.getImage();
public MainCell()
{
Dimension dim = new Dimension(17, 17);
setPreferredSize(dim);
addMouseListener(this);
}
public void activate()
{
setBackground(MainGUI.userColor);
System.out.println(getName()+" "+posX+","+posY+" activated");
setActivated(true);
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if(getPosX()==MainGUI.columns-1&&getPosY()==0)
{
//do nothing
}
else if(getPosY()!=0&&getPosX()!=MainGUI.columns-1)
{
g.drawImage(cellImage_1,0,0,null);
}
else if(getPosY()==0)
{
g.drawImage(cellImage_2,0,0,null);
}
else if(getPosX()==MainGUI.columns-1)
{
g.drawImage(cellImage_3,0,0,null);
}
}
public void setActivated(boolean b)
{
activated = b;
}
public void deactivate()
{
setBackground(Color.gray);
System.out.println(getName()+" "+posX+","+posY+" deactivated");
setActivated(false);
}
public boolean isActivated()
{
return activated;
}
public void setNeighbors(int i)
{
neighbors = i;
}
public int getNeighbors()
{
return neighbors;
}
public int getPosX()
{
return posX;
}
public void setPosX(int x)
{
posX = x;
}
public int getPosY()
{
return posY;
}
public void setPosY(int y)
{
posY = y;
}
public void mouseClicked(MouseEvent e)
{
}
public void mouseEntered(MouseEvent e)
{
if(leftMousePressed&&SwingUtilities.isLeftMouseButton(e))
{
activate();
}
if(rightMousePressed&&SwingUtilities.isRightMouseButton(e))
{
deactivate();
}
}
public void mouseExited(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
if(SwingUtilities.isRightMouseButton(e)&&!leftMousePressed)
{
deactivate();
rightMousePressed = true;
}
if(SwingUtilities.isLeftMouseButton(e)&&!rightMousePressed)
{
activate();
leftMousePressed = true;
}
}
public void mouseReleased(MouseEvent e)
{
if(SwingUtilities.isRightMouseButton(e))
{
rightMousePressed = false;
}
if(SwingUtilities.isLeftMouseButton(e))
{
leftMousePressed = false;
}
}
}
The following is SizeChooser.java:
import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import javax.swing.*;
public class SizeChooser extends JFrame
{
private static final long serialVersionUID = -6431709376438241788L;
public static MainGUI GUI;
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
JTextField rowsTextField = new JTextField(String.valueOf((screenSize.height/17)-15));
JTextField columnsTextField = new JTextField(String.valueOf((screenSize.width/17)-10));
private static int rows = screenSize.height/17-15;
private static int columns = screenSize.width/17-10;
public SizeChooser()
{
setResizable(false);
setTitle("Select a size!");
JPanel container = new JPanel();
BoxLayout containerLayout = new BoxLayout(container, BoxLayout.PAGE_AXIS);
container.setLayout(containerLayout);
add(container);
JLabel rowsLabel = new JLabel("Rows:");
container.add(rowsLabel);
container.add(rowsTextField);
JLabel columnsLabel = new JLabel("Columns:");
container.add(columnsLabel);
container.add(columnsTextField);
JButton confirmSize = new JButton("Confirm");
confirmSize.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
GUI.setVisible(false);
GUI = null;
if(Integer.parseInt(rowsTextField.getText())>0)
{
rows = Integer.parseInt(rowsTextField.getText());
}
else
{
JOptionPane.showMessageDialog(rootPane, "Please use a value greater than 0!","Rules:",JOptionPane.ERROR_MESSAGE);
}
if(Integer.parseInt(columnsTextField.getText())>0)
{
columns = Integer.parseInt(columnsTextField.getText());
}
else
{
JOptionPane.showMessageDialog(rootPane, "Please use a value greater than 0!","Rules:",JOptionPane.ERROR_MESSAGE);
}
GUI = new MainGUI("The Game of Life!", rows, columns);
GUI.setLocationRelativeTo(null);
GUI.setVisible(true);
setVisible(false);
}
});
container.add(confirmSize);
URL imgURL = getClass().getResource("images/gol.gif");
ImageIcon icon = new ImageIcon(imgURL);
System.out.println(icon);
setIconImage(icon.getImage());
pack();
}
public static void main(String[]args)
{
GUI = new MainGUI("The Game of Life!", rows, columns);
GUI.setLocationRelativeTo(null);
GUI.setVisible(true);
}
}
So the problem now is, when the randomize button is pressed, or a large number of cells exist and then the timer is started, the cells aren't as snappy as they would be with less active cells. For example, with 100 columns and 50 rows, when the randomize button is pressed, one cell activates, then the next, then another, and so forth. Can I have them all activate at exactly the same time? Is this just a problem with too many things calculated at once? Would concurrency help?
QUICK EDIT: Is the swing timer the best idea for this project?
I havent read through your code completely but I am guessing that your listener methods are fairly computationally intensive and hence the lag in updating the display.
This simple test reveals that your randomize operation should be fairly quick:
public static void main(String args[]) {
Random rn = new Random();
boolean b[] = new boolean[1000000];
long timer = System.nanoTime();
for (int i = 0; i < b.length; i++) {
b[i] = rn.nextInt(6) == 0;
}
timer = System.nanoTime() - timer;
System.out.println(timer + "ns / " + (timer / 1000000) + "ms");
}
The output for me is:
17580267ns / 17ms
So this leads me into thinking activate() or deactivate() is causing your UI to be redrawn.
I am unable to run this because I don't have your graphical assets, but I would try those changes to see if it works:
In MainGUI#actionPerformed, change:
if(e.getActionCommand().equals("randomize"))
{
Random rn = new Random();
for(int i=0;i<totalCells;i++)
{
cell[i].deactivate();
if(rn.nextInt(6)==0)
{
cell[i].activate();
}
}
}
to:
if(e.getActionCommand().equals("randomize"))
{
Random rn = new Random();
for(int i=0;i<totalCells;i++)
{
// This will not cause the object to be redrawn and should
// be a fairly cheap operation
cell[i].setActivated(rn.nextInt(6)==0);
}
// Cause the UI to repaint
repaint();
}
Add this to MainCell
// You can specify those colors however you like
public static final Color COLOR_ACTIVATED = Color.RED;
public static final Color COLOR_DEACTIVATED = Color.GRAY;
And change:
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if(getPosX()==MainGUI.columns-1&&getPosY()==0)
{
//do nothing
}
to:
protected void paintComponent(Graphics g)
{
// We now make UI changes only when the component is painted
setBackground(activated ? COLOR_ACTIVATED : COLOR_DEACTIVATED);
super.paintComponent(g);
if(getPosX()==MainGUI.columns-1&&getPosY()==0)
{
//do nothing
}

Swing Timers and Animations in JPanel

Im trying to animate 2 boxes to go from the top right to the bottom left of a JPanel. For the animation I'm using a Swing Timer and SwingUtilities.invokeLater(). The problem is that when I click the start button. It only animates and moves the blue box, but not the red one.
Heres the code:
//import neccessary stuff
public class Example extends JFrame {
public static void main(String[] args) {
Example e = new Example();
e.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
e.setSize(600, 565);
e.setVisible(true);
}</code>
private JButton startButton = new JButton("Start");
private JPanel theTable = new table();
public Example() {
add(startButton, BorderLayout.SOUTH);
add(theTable, BorderLayout.CENTER);
Handler handler = new Handler();
startButton.addActionListener(handler);
}
public ArrayList<Integer> xPos, yPos;
final int START_POSITION_X = 470;
final int START_POSITION_Y = 10;
final int[] END_POSITION_X = {70, 87};
final int END_POSITION_Y = 160;
private class table extends JPanel {
public table() {
xPos = new ArrayList<Integer>();
yPos = new ArrayList<Integer>();
xPos.add(START_POSITION_X); //default position for box1
yPos.add(START_POSITION_Y);
xPos.add(START_POSITION_X); //default position for box2
yPos.add(START_POSITION_Y);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(new Color(-16756217));
g.setColor(Color.RED);
g.fillRect(xPos.get(1), yPos.get(1), 89, 129);
g.setColor(Color.BLUE);
g.fillRect(xPos.get(0), yPos.get(0), 89, 129);
if (isAnimating) {
animator.start();
} else {
animator.stop();
isAnimating = false;
}
}
}
private class Handler implements ActionListener {
public void actionPerformed(ActionEvent e) {
Runnable r1 = new Runnable() {
#Override
public void run() {
animateCard(0, END_POSITION_X[0], END_POSITION_Y);
}
};
SwingUtilities.invokeLater(r1);
animateCard(1, END_POSITION_X[1], END_POSITION_Y);
}
}
public void animateCard(int card, int xDest, int yDest) {
cardID = card;
xDestination = xDest;
yDestination = yDest;
totalXDistance = Math.abs(xDestination - START_POSITION_X);
totalYDistance = Math.abs(yDestination - START_POSITION_Y);
animator.start();
}
int cardID;
int xDestination, yDestination, totalXDistance, totalYDistance;
boolean isAnimating = false;
Timer animator = new Timer(15, new ActionListener() {
int startVel = 20;
public void actionPerformed(ActionEvent e) {
double xRelDistance, xAbsDistance, xVel;
int xRealVel;
xAbsDistance = xDestination - xPos.get(cardID);
xRelDistance = xAbsDistance / totalXDistance;
xVel = startVel * xRelDistance;
double yRelDistance, yAbsDistance, yVel;
yAbsDistance = yDestination - yPos.get(cardID);
yRelDistance = yAbsDistance / totalYDistance;
yVel = startVel * yRelDistance;
if (xVel > 0) {
xRealVel = (int) java.lang.Math.ceil(xVel);
} else {
xRealVel = (int) java.lang.Math.floor(xVel);
}
xPos.set(cardID, xPos.get(cardID) + xRealVel);
int yRealVel;
if (xVel > 0) {
yRealVel = (int) java.lang.Math.ceil(yVel);
yPos.set(cardID, yPos.get(cardID) + yRealVel);
} else {
yRealVel = (int) java.lang.Math.floor(yVel);
}
yPos.set(cardID, yPos.get(cardID) + yRealVel);
if ((xPos.get(cardID) == xDestination) && (yPos.get(cardID) == yDestination)) {
isAnimating = false;
} else {
isAnimating = true;
}
repaint();
}
});
}
So all of those variable declared at the class level are shared... Your first call to animateCard will set them and then your second call to animateCard is going to completely overwrite the previous values. You need to change them from class variables to parameters of the animation.
Create a new class AnimationTask that implements ActionListener and save the variables in that class.
E.g.,
class AnimationTask implements ActionListener {
private int cardID;
private int xDest;
private int yDest;
private int totalXDistance;
private int totalYDistance;
public AnimationTask(int cardID, int xDest, int yDest) {
this.cardID = cardID;
this.xDest = xDest;
this.yDest = yDest;
this.totalXDistance = Math.abs(xDestination - START_POSITION_X);
this.totalYDistance = Math.abs(yDestination - START_POSITION_Y);
}
public void actionPerformed(ActionEvent e) {
// do your animation logic...
}
}
and use that custom class in your "animator"
E.g.,
Timer animator = new Timer(15, new AnimationTask(cardId, xDest, yDest);
put
animateCard(1, END_POSITION_X[1], END_POSITION_Y);
inside your run method:
public void run() {
animateCard(0, END_POSITION_X[0], END_POSITION_Y);
}

Minesweeper Action Events

Is there a way to make certain event actions specific to left and right mouse clicks?
I'm creating a minesweeper gui, so when a square is left-clicked it will be uncovered, & when it's right-clicked it will be flagged.
I wasn't sure how to syntactically check for this & couldn't find it on the tut.
Thanks for the help!
I decided to give it a go, to try to create a simple Mine Sweeper application, one without a timer or reset (yet), but that is functional and uses both a GUI cell class and a non-GUI model class (it can't be copied and used in for intro to Java homework).
Edit 1: now has reset capability:
MineSweeper.java: holds the main method and starts the JFrame
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel(){{add(resetButton);}});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
//frame.getContentPane().add(new MineSweeper(20, 20, 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
MineCellGrid.java: the class that displays the grid of mine cells and times them all together.
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<MineCell>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
MineCellGridModel.java: the non-GUI model for the MineCellGrid
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JOptionPane;
public class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r
* cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements
PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations", JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
MineCell.java: the class that I started on. Uses the model class as its non-GUI nucleus.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
/**
* http://stackoverflow.com/questions/7006029/minesweeper-action-events
*
* #author Pete
*/
#SuppressWarnings("serial")
public class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? "" : String
.valueOf(model.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
MineCellModel.java: the non-GUI model for the mine cell
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED,
-1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE,
oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
Here's the whole program combined into a single MCVE file, MineSweeper.java:
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel() {
{
add(resetButton);
}
});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
// frame.getContentPane().add(new MineSweeper(20, 20,
// 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
#SuppressWarnings("serial")
class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r * cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations",
JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
#SuppressWarnings("serial")
class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? ""
: String.valueOf(model.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE, oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
If you are using swing then
Is there a way to make certain event actions specific to left and
right mouse clicks?
Implement a MouseListener no component. Then in implemented method you have a MouseEvent object which has a getButton() method which tells you which mouse is pressed.
Edit
OP has asked following question but now removed it.
Is this gui nested inside the other in an action event, when
game_lost becomes true?
You can open a JDialog for this.
You may be interested in the MouseEvent Class of java.awt.event. here

Categories