I'm trying to implement the game dots and boxes by using 3 JLabel arrays:
the dots for the game board.
the vertical lines
the horizontal lines
the ide is when you click using MouseInputAdapter to get the coordinates of the mouse the it should check if the coordinates of mouse point are in one of the labels of the verticals or horizontal lines. But when I run the program my JPanel is completly empty. And other times when I run it and it's not empty all the labels just vanish after I click.
package gameframes;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.event.MouseInputAdapter;
import java.awt.Color;
public class LinesAndBoxesFrame extends JFrame {
JLabel[][] dots = new JLabel[8][8];
JLabel[][] herizontalLines = new JLabel[8][7];
JLabel[][] verticallLines = new JLabel[8][7];
public LinesAndBoxesFrame(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(620, 640);
setLocationRelativeTo(null);
setVisible(true);
setLayout(null);
JPanel p=new JPanel();
p.setSize(600,600);
add(p);
for (int i = 0; i < dots.length; i++) {
for (int j = 0; j < dots.length; j++) {
dots[i][j] = new JLabel();
dots[i][j].setBounds(20 + i * (20 + 50), 20 + j * (20 + 50), 20, 20);
dots[i][j].setOpaque(true);
dots[i][j].setBackground(Color.red);
p.add(dots[i][j]);
p.repaint();
}
}
for (int i = 0; i < herizontalLines.length; i++) {
for (int j = 0; j < herizontalLines[0].length; j++) {
herizontalLines[i][j] = new JLabel();
herizontalLines[i][j].setBounds(40 + j * (20 + 50), 20 + i * (20 + 50), 50, 20);
herizontalLines[i][j].setOpaque(true);
herizontalLines[i][j].setBackground(Color.green);
herizontalLines[i][j].setVisible(false);
p.add(herizontalLines[i][j]);
p.repaint();
}
}
for (int i = 0; i < verticallLines.length; i++) {
for (int j = 0; j < verticallLines[0].length; j++) {
verticallLines[i][j] = new JLabel();
verticallLines[i][j].setBounds(20 + i * (20 + 50), 40 + j * (20 + 50), 20, 50);
verticallLines[i][j].setOpaque(true);
verticallLines[i][j].setBackground(Color.green);
verticallLines[i][j].setVisible(false);
p.add(verticallLines[i][j]);
p.repaint();
}
}
p.addMouseListener(new MouseInputAdapter() {
int count = 0;
#Override
public void mouseClicked(MouseEvent e) {
int mX = e.getX();
int mY = e.getY();
System.out.println(mX);
System.out.println(mY);
boolean b = false;
for (JLabel[] l : herizontalLines) {
for (JLabel l1 : l) {
b = checkBounds(l1, mX, mY);
if (b) {
l1.setVisible(true);
break;
}
}
}
if (!b) {
for (JLabel[] l : verticallLines) {
for (JLabel l1 : l) {
b = checkBounds(l1, mX, mY);
if (b) {
l1.setVisible(true);
break;
}
}
}
}
System.out.println(b + " metod finished! " + count);
p.revalidate();
p.repaint();
count++;
}
});
// add(p);
// repaint();
p.revalidate();
p.repaint();
}
public boolean checkBounds(JLabel l, int x, int y) {
return (x >= l.getX() && x <= l.getX() + l.getWidth()) && (y >= l.getY() && y <= l.getY() + l.getHeight());
}
public static void main(String[] args) {
new LinesAndBoxesFrame("Dots and Boxes");
}
}
Update:
I just needed to set the layout of my JPanel to null and that fixes it.
I'm using the java.awt graphics class, and I'm trying to make rows and squares.
I can't seem to get the layout of the rows correctly.
I'm trying to code 8 rows with 3 columns each. However, I just get 2 rows with 12 columns.
If somebody can help me to create the outcome that I want, that would be greatly appreciated.
Here's my code:
g.setColor(Color.WHITE);
int x = 70;
int y = 80;
int w = 30;
int h = 35;
for(int row = 0; row < 3; row++) {
for(int col = 0; col < 4; col++) {
g.fillRect( x, y, w, h );
g.fillRect( x, y + h + 20, w, h );
x += w + 15;
}
System.out.println();
}
Here's the output: 2 rows, 12 columns of squares
Beware of how you are updating your position information. For example, you should only be updating the x position in the inner loop and resetting to 0 before entering the inner loop, and the y position should only be updated on each new row.
Alternatively, you could calculate the position directly, based on the row/column index and the row/column height, as demonstrated below.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
private static int COLUMN_COUNT = 3;
private static int ROW_COUNT = 8;
private static int COLUMN_WIDTH = 30;
private static int ROW_HEIGHT = 35;
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3 * COLUMN_WIDTH, 8 * ROW_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int columnWidth = getWidth() / 3;
int rowHeight = getHeight() / 8;
int x = 0;
int y = 0;
for (int row = 0; row < ROW_COUNT; row++) {
for (int col = 0; col < COLUMN_COUNT ; col++) {
if (col % 2 == 0) {
x = columnWidth * col;
y = rowHeight * row;
g2d.fillRect(x + 2, y + 2, columnWidth - 4, rowHeight - 4);
}
}
}
g2d.dispose();
}
}
}
I'm creating a battleships program for java. Using a gridlayout I want to have the player board in the west panel and NPC board in the east panel (as well as some other info and means of input in the centre panel and the south panel).
I started by adding the players board like follows (full code can be found at the bottom of this post as well):
public void placePlyrGrids()
{
plyrBoard.add(cornerGridLabel); //add an empty grid to the top left
for(n = 0; n < 10; n++)
plyrBoard.add(letterGridLabels[n]); //the first row is the first 10 letters of the alphabet
for (y = 1; y < 11; y++) //For every (y) row...
{
for (x = 0; x < 11; x++) //...add ten (x) grids to make columns
{
if (x == 0) //To the start of each row, add a number (image JLabel)
{
plyrBoard.add(numberGridLabels[numberCounter]);
numberCounter++;
}
else //for the rest of each row, add buttons
{
plyrBoard.add(buttonGrids[y-1][x-1]);
}
}
}
}
This worked fine.
Then I tried adding the dealer board in two ways, none of which seemed to work, as they both got messed up, and seemed to mess up the player board as well which had seemed to work fine on its own.
1: Placing both boards simultaneously in the same method.
public void placeBoards()
{
plyrBoard.add(cornerGridLabel); //add an empty grid to the top left
NPCBoard.add(cornerGridLabel);
for(n = 0; n < 10; n++)
plyrBoard.add(letterGridLabels[n]); //the first row is the first 10 letters of the alphabet
NPCBoard.add(letterGridLabels[n]);
for (y = 1; y < 11; y++) //For every (y) row...
{
for (x = 0; x < 11; x++) //...add ten (x) grids to make columns
{
if (x == 0) //To the start of each row, add a number (image JLabel)
{
plyrBoard.add(numberGridLabels[numberCounter]);
NPCBoard.add(numberGridLabels[numberCounter]);
numberCounter++;
}
else //for the rest of each row, add buttons
{
plyrBoard.add(buttonGrids[y-1][x-1]);
NPCBoard.add(emptyGridLabel);
}
}
}
}
2: Placing both each in a different method (used in combination with the pladePlyrGrids method at the top)
public void placeNPCGrids()
{
NPCBoard.add(cornerGridLabel);
for(n = 0; n < 10; n++)
NPCBoard.add(letterGridLabels[n]);
for (y = 1; y < 11; y++)
{
for (x = 0; x < 11; x++)
{
if (x == 0)
{
NPCBoard.add(numberGridLabels[numberCounter]);
numberCounter++;
}
else
{
NPCBoard.add(emptyGridLabel);
}
}
}
}
My full code:
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Battleships {
public static void main(String[] args)
{
Interface Win = new Interface ();
}
}
class Interface extends JFrame implements ActionListener
{
//Identify variables
int n;
int numberCounter = 0;
int y;
int x;
// lengths of the various ships in the game
//ADD IMAGE COMPONENTS
//Coordinate axes and empty grids
ImageIcon emptyGrid = new ImageIcon("EmptyGrid.png");
ImageIcon cornerGrid = new ImageIcon("CornerGrid.png");
ImageIcon [] numberGrids = new ImageIcon[11];
{
for (n = 0; n < 11; n ++)
numberGrids[n] = new ImageIcon("Grid" + (n + 1) + ".png");
}
ImageIcon [] letterGrids = new ImageIcon [11];
{
for (n = 0; n < 11; n ++)
letterGrids[n] = new ImageIcon("GridA" + (n + 1)+ ".png");
}
//Ship parts
//Clickable ships (for placement)
ImageIcon fullBattleship = new ImageIcon("FullBattleship.png");
ImageIcon fullCruiser = new ImageIcon("FullCruiser.png");
ImageIcon fullPatrolBoat1 = new ImageIcon("FullPatrolBoat.png");
ImageIcon fullPatrolBoat2 = new ImageIcon("FullPatrolBoat.png");
//JLabels
JLabel cornerGridLabel = new JLabel(cornerGrid);
JLabel [] numberGridLabels = new JLabel[10];
{
//The first 11 grids are an empty grid followed by letters A-J
for (n = 0; n < 10; n++)
{
numberGridLabels[n] = new JLabel(numberGrids[n]);
}
}
JLabel [] letterGridLabels = new JLabel [10];
{
for (n = 0; n < 10; n ++)
{
letterGridLabels[n] = new JLabel (letterGrids[n]);
}
}
JLabel emptyGridLabel = new JLabel(emptyGrid);
JButton [][] buttonGrids = new JButton [10][10];
{
for (y = 0; y < 10; y++)
{
for (x = 0; x < 10; x++)
{
buttonGrids[x][y] = new JButton(emptyGrid);
buttonGrids[x][y].setPreferredSize(new Dimension(50,50));
}
}
}
JLabel [] NPCGrids = new JLabel[121]; //grid placements for the dealer board
{
for (n = 0; n < 121; n ++)
NPCGrids[n] = new JLabel (emptyGrid);
}
JLabel [] clickableBoats = new JLabel [4];
{
clickableBoats[0] = new JLabel (fullBattleship);
clickableBoats[1] = new JLabel (fullCruiser);
clickableBoats[2] = new JLabel (fullPatrolBoat1);
clickableBoats[3] = new JLabel (fullPatrolBoat2);
}
JButton [] plyrClickableGrids = new JButton [100];
{
for (n = 0; n < 99; n++);
plyrClickableGrids[n] = new JButton(emptyGrid);
}
//Add interface components
JTextArea playerInformation = new JTextArea(20,5);
JScrollPane textPane1 = new JScrollPane (playerInformation);
JButton playTurnBtn = new JButton ("Play Turn");
//add JPanels
JPanel plyrBoard = new JPanel (new GridLayout(11,11));
JPanel infoPanel = new JPanel(new GridLayout(1,1));
JPanel NPCBoard = new JPanel(new GridLayout(11,11));
JPanel inputPanel = new JPanel(new GridLayout(1,10));
public Interface ()
{
super ("Battleships");
setSize (1367,729);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
//Set the background color
Container contentArea = getContentPane();
//Set each panel to "opaque", so that the background becomes visible
plyrBoard.setOpaque(false);
NPCBoard.setOpaque(false);
inputPanel.setOpaque(false);
setVisible (true);
playerInformation.setEditable(false);
//Add panels to different compass points on the content area
contentArea.add("West", plyrBoard);
contentArea.add("Center", infoPanel);
contentArea.add("East", NPCBoard);
contentArea.add("South", inputPanel);
//Add imageLabels and buttons to panels
placePlyrGrids();
numberCounter = 0;
placeNPCGrids();
infoPanel.add(playerInformation);
for (n = 0; n < 4; n++)
{
inputPanel.add(clickableBoats[n]);
}
inputPanel.add(playTurnBtn);
// TODO Vanity
//Button format
playTurnBtn.setPreferredSize(new Dimension(1, 141));
}
public void placePlyrGrids()
{
plyrBoard.add(cornerGridLabel); //add an empty grid to the top left
//NPCBoard.add(cornerGridLabel);
for(n = 0; n < 10; n++)
plyrBoard.add(letterGridLabels[n]); //the first row is the first 10 letters of the alphabet
//NPCBoard.add(letterGridLabels[n]);
for (y = 1; y < 11; y++) //For every (y) row...
{
for (x = 0; x < 11; x++) //...add ten (x) grids to make columns
{
if (x == 0) //To the start of each row, add a number (image JLabel)
{
plyrBoard.add(numberGridLabels[numberCounter]);
//NPCBoard.add(numberGridLabels[numberCounter]);
numberCounter++;
}
else //for the rest of each row, add buttons
{
plyrBoard.add(buttonGrids[y-1][x-1]);
//NPCBoard.add(emptyGridLabel);
}
}
}
}
public void placeNPCGrids()
{
NPCBoard.add(cornerGridLabel);
for(n = 0; n < 10; n++)
NPCBoard.add(letterGridLabels[n]);
for (y = 1; y < 11; y++)
{
for (x = 0; x < 11; x++)
{
if (x == 0)
{
NPCBoard.add(numberGridLabels[numberCounter]);
numberCounter++;
}
else
{
NPCBoard.add(emptyGridLabel);
}
}
}
}
public void actionPerformed(ActionEvent e)
{
}
}
As I'm sure you understand by now I am very confused with this and I don't understand at all why this is happening. After all, the first method works fine on its own. Why shouldn't the second one and why are they destroying each other?
Any suggestions or tips to help put me in the right direction would be very appreciated.
Edit:
Solution:
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Battleships {
public static void main(String[] args)
{
Interface Win = new Interface ();
}
}
class Interface extends JFrame implements ActionListener
{
//Identify variables
int n;
int numberCounter = 0;
int y;
int x;
// lengths of the various ships in the game
//ADD IMAGE COMPONENTS
//Coordinate axes and empty grids
ImageIcon emptyGrid = new ImageIcon("EmptyGrid.png");
ImageIcon cornerGrid = new ImageIcon("CornerGrid.png");
ImageIcon [] numberGrids = new ImageIcon[11];
{
for (n = 0; n < 11; n ++)
numberGrids[n] = new ImageIcon("Grid" + (n + 1) + ".png");
}
ImageIcon [] letterGrids = new ImageIcon [11];
{
for (n = 0; n < 11; n ++)
letterGrids[n] = new ImageIcon("GridA" + (n + 1)+ ".png");
}
//Ship parts
//Clickable ships (for placement)
ImageIcon fullBattleship = new ImageIcon("FullBattleship.png");
ImageIcon fullCruiser = new ImageIcon("FullCruiser.png");
ImageIcon fullPatrolBoat1 = new ImageIcon("FullPatrolBoat.png");
ImageIcon fullPatrolBoat2 = new ImageIcon("FullPatrolBoat.png");
//JLabels
JLabel plyrCornerGridLabel = new JLabel(cornerGrid);
JLabel [] plyrNumberGridLabels = new JLabel[10];
{
//The first 11 grids are an empty grid followed by letters A-J
for (n = 0; n < 10; n++)
{
plyrNumberGridLabels[n] = new JLabel(numberGrids[n]);
}
}
JLabel [] plyrLetterGridLabels = new JLabel [10];
{
for (n = 0; n < 10; n ++)
{
plyrLetterGridLabels[n] = new JLabel (letterGrids[n]);
}
}
JLabel NPCCornerGridLabel = new JLabel(cornerGrid);
JLabel [] NPCNumberGridLabels = new JLabel[10];
{
//The first 11 grids are an empty grid followed by letters A-J
for (n = 0; n < 10; n++)
{
NPCNumberGridLabels[n] = new JLabel(numberGrids[n]);
}
}
JLabel [] NPCLetterGridLabels = new JLabel [10];
{
for (n = 0; n < 10; n ++)
{
NPCLetterGridLabels[n] = new JLabel (letterGrids[n]);
}
}
JLabel[][] emptyGridLabels = new JLabel [10][10];
{
for (y = 0; y < 10; y++)
{
for (x = 0; x < 10; x++)
{
emptyGridLabels[x][y] = new JLabel(emptyGrid);
}
}
}
JButton [][] buttonGrids = new JButton [10][10];
{
for (y = 0; y < 10; y++)
{
for (x = 0; x < 10; x++)
{
buttonGrids[x][y] = new JButton(emptyGrid);
buttonGrids[x][y].setPreferredSize(new Dimension(50,50));
}
}
}
JLabel [] NPCGrids = new JLabel[121]; //grid placements for the dealer board
{
for (n = 0; n < 121; n ++)
NPCGrids[n] = new JLabel (emptyGrid);
}
JLabel [] clickableBoats = new JLabel [4];
{
clickableBoats[0] = new JLabel (fullBattleship);
clickableBoats[1] = new JLabel (fullCruiser);
clickableBoats[2] = new JLabel (fullPatrolBoat1);
clickableBoats[3] = new JLabel (fullPatrolBoat2);
}
JButton [] plyrClickableGrids = new JButton [100];
{
for (n = 0; n < 99; n++);
plyrClickableGrids[n] = new JButton(emptyGrid);
}
//Add interface components
JTextArea playerInformation = new JTextArea(20,5);
JScrollPane textPane1 = new JScrollPane (playerInformation);
JButton playTurnBtn = new JButton ("Play Turn");
//add JPanels
JPanel plyrBoard = new JPanel (new GridLayout(11,11));
JPanel infoPanel = new JPanel(new GridLayout(1,1));
JPanel NPCBoard = new JPanel(new GridLayout(11,11));
JPanel inputPanel = new JPanel(new GridLayout(1,10));
public Interface ()
{
super ("Battleships");
setSize (1367,729);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
//Set the background color
Container contentArea = getContentPane();
//Set each panel to "opaque", so that the background becomes visible
plyrBoard.setOpaque(false);
NPCBoard.setOpaque(false);
inputPanel.setOpaque(false);
setVisible (true);
playerInformation.setEditable(false);
playTurnBtn.setPreferredSize(new Dimension(1, 141));
//Add panels to different compass points on the content area
contentArea.add("West", plyrBoard);
contentArea.add("Center", infoPanel);
contentArea.add("East", NPCBoard);
contentArea.add("South", inputPanel);
//Add imageLabels and buttons to panels
infoPanel.add(playerInformation);
for (n = 0; n < 4; n++)
{
inputPanel.add(clickableBoats[n]);
}
inputPanel.add(playTurnBtn);
placePlyrGrids();
numberCounter = 0;
placeNPCGrids();
// TODO Vanity
//Button format
}
public void placePlyrGrids()
{
plyrBoard.add(plyrCornerGridLabel); //add an empty grid to the top left
//NPCBoard.add(cornerGridLabel);
for(n = 0; n < 10; n++)
plyrBoard.add(plyrLetterGridLabels[n]); //the first row is the first 10 letters of the alphabet
//NPCBoard.add(NPCLetterGridLabels[n]);
for (y = 1; y < 11; y++) //For every (y) row...
{
for (x = 0; x < 11; x++) //...add ten (x) grids to make columns
{
if (x == 0) //To the start of each row, add a number (image JLabel)
{
plyrBoard.add(plyrNumberGridLabels[numberCounter]);
//NPCBoard.add(NPCNumberGridLabels[numberCounter]);
numberCounter++;
}
else //for the rest of each row, add buttons
{
plyrBoard.add(buttonGrids[y-1][x-1]);
//NPCBoard.add(emptyGridLabel);
}
}
}
}
public void placeNPCGrids()
{
NPCBoard.add(NPCCornerGridLabel);
for(n = 0; n < 10; n++)
NPCBoard.add(NPCLetterGridLabels[n]);
for (y = 1; y < 11; y++)
{
for (x = 0; x < 11; x++)
{
if (x == 0)
{
NPCBoard.add(NPCNumberGridLabels[numberCounter]);
numberCounter++;
}
else
{
NPCBoard.add(emptyGridLabels[x-1][y-1]);
}
}
}
}
public void actionPerformed(ActionEvent e)
{
}
}
The issue is that in all the code you are always referring to the same object, E.G.
public void placeBoards()
{
//Both player board and npc board are going to have the same cornerGirdLabel, you should be creating two separate instances of it
plyrBoard.add(cornerGridLabel); //add an empty grid to the top left
NPCBoard.add(cornerGridLabel);
//Rest of the code
}
All the way through your code, you keep using the reference to the same objects, which is not going to help you when you want to build two boards with their own grids!
It might be better, especially for readability to separate your board building into different classes and have them create their own instances of these objects, rather than trying to fit this all in one class with your main method. Have a look at some best design practice documents. for example, they have some nice tips here
I have to write a program that will generate 20 random circles with random radius lengths. If any of these circles intersect with another, the circle must be blue, and if it does not intersect, the color is red. I must also place a button on the JFrame. If this button is pressed, it needs to clear out the JFrame, and generate a new set of 20 circles following the same color rules. I am extremely new to Java Swing and am really stuck. I have everything working except the button. I cannot get a new set of circles to generate. Any help would be greatly appreciated. Thank You.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
setPreferredSize(new Dimension(1000, 800)); // set window size
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
// Add button to run again
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
add(btnAgain);
btnAgain.addActionListener(new ButtonClickListener());
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if(action.equals("Run Again"))
{
new IntersectingCircles();
}
}
}
}
Suggestions:
Give your class a method that creates the random circles and calls repaint()
This method should create the circles and add them into an ArrayList.
Consider using Ellipse2D to represent your circles, and so you'd have an ArrayList<Ellipse2D>.
Call this method in your class constructor.
Call it again in the button's ActionListener.
Never add button's or change the state of your class from within your paintComponent method. This method is for drawing the circles and drawing them only and nothing more. Your way you will be creating the button each time the paintComponent method is called, so you could be potentially needlessly creating many JButtons
and needlessly slowing down your time-critical painting method.
Instead add the button in the constructor.
Be sure to call super.paintComponent(g) in your paintComponent method as its first call. This will clear the old circles when need be.
Also in paintComponent, iterate through the ArrayList of circles, drawing each one.
After some searching on this website, i found what i needed. Everything seems to work now. Thanks.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1000, 800));
ActionListener runAgain = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent c)
{
frame.getContentPane().add(new IntersectingCircles());
frame.pack();
}
};
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
btnAgain.addActionListener(runAgain);
frame.add(btnAgain);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
Maybe you can have a try...
I'm getting the feeling that I have no idea how swing Timer works. I'm still new to the Java GUI API, and the program I'm writing is just to test myself and help me familiarize myself more with its inner workings.
What it's supposed to do is wait until the user presses the Start button, then iterate the display (a grid of white or black JPanels), which displays a simple cellular automata simulation at a 1 second interval, and pauses when the Pause button is pressed (same as the Start button, but changes name). Each cell in the grid is supposed to start with a random color (white/black). What it's instead doing is to pause for a half second or so, then "run" for another half second, then pause, then run, so on and so forth.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CA_Driver extends JFrame{
private JPanel gridPanel, buttonPanel;
private JButton start_pause, pause;
private static Timer timer;
private Color black = Color.black;
private Color white = Color.white;
static Color[][] currentGrid, newGrid;
static Cell[][] cellGrid;
static boolean run, stop;
static int height = 20, width = 30, state;
public CA_Driver(){
stop = false;
run = false;
currentGrid = new Color[height][width];
newGrid = new Color[height][width];
cellGrid = new Cell[height][width];
//Initialize grid values
for (int x = 0; x < currentGrid.length; x++)
for (int y = 0; y < currentGrid[x].length; y++){
int z = (int) (Math.random() * 2);
if (z == 0)
currentGrid[x][y] = newGrid[x][y] = white;
else currentGrid[x][y] = newGrid[x][y] = black;
}
//Create grid panel
gridPanel = new JPanel();
gridPanel.setLayout(new GridLayout(height,width));
//Populate grid
for (int x = 0; x < newGrid.length; x++)
for (int y = 0; y < newGrid[x].length; y++){
cellGrid[x][y] = new Cell(x,y);
cellGrid[x][y].setBackground(newGrid[x][y]);
int z = (int) Math.random();
if (z == 0) cellGrid[x][y].setBackground(black);
else cellGrid[x][y].setBackground(currentGrid[x][y]);
gridPanel.add(cellGrid[x][y]);
}
//Create buttons
state = 0;
start_pause = new JButton();
start_pause.setText("Start");
start_pause.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
if (state == 0) {
start_pause.setText("Pause");
run = true;
timer.start();
state += 1;
}
else {
start_pause.setText("Start");
run = false;
timer.stop();
state -= 1;
}
}
});
buttonPanel = new JPanel(new BorderLayout());
buttonPanel.add(start_pause, BorderLayout.NORTH);
// buttonPanel.add(pause, BorderLayout.EAST);
//Initialize and display frame
this.add(gridPanel, BorderLayout.NORTH);
this.add(buttonPanel, BorderLayout.SOUTH);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
//this.setSize(500, 500);
pack();
this.setVisible(true);
//Initialize timer
timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
for (int x = 0; x < cellGrid.length; x++)
for (int y = 0; y < cellGrid[x].length; y++){
cellGrid[x][y].setColor();
currentGrid[x][y] = newGrid[x][y];
}
//Display processing for next frame
for (int x = 0; x < currentGrid.length; x++)
for (int y = 0; y < currentGrid[x].length; y++){
int b = checkNeighbors(y,x);
if (b > 4 || b < 2)
newGrid[x][y] = black;
else newGrid[x][y] = white;
}
if(!run) timer.stop();
}
});
}
public static void main(String[] args) {
new CA_Driver();
}
private int checkNeighbors(int w, int h){
int b = 0;
//Top Left
if((w != 0) && (h != 0) && (currentGrid[h - 1][w - 1] == black))
b++;
//Top Middle
if((h != 0) && (currentGrid[h - 1][w] == black))
b++;
//Top Right
if((w != width - 1) && (h != 0) && (currentGrid[h - 1][w + 1] == black))
b++;
//Middle Left
if((w != 0) && (currentGrid[h][w - 1] == black))
b++;
//Middle Right
if((w != width - 1) && (currentGrid[h][w + 1] == black))
b++;
//Bottom left
if((w != 0) && (h != height - 1) && (currentGrid[h + 1][w - 1] == black))
b++;
//Bottom Middle
if((h != height - 1) && (currentGrid[h + 1][w] == black))
b++;
//Bottom Right
if((w != width - 1) && (h != height - 1) && (currentGrid[h + 1][w + 1] == black))
b++;
return b;
}
private class Cell extends JPanel{
private Color c;
private int posx, posy;
public Cell(int x, int y){
posx = x;
posy = y;
}
public Point getLocation(){
return new Point(posx, posy);
}
public void setColor(){
c = newGrid[posx][posy];
setBackground(c);
}
public Dimension getPreferredSize(){
return new Dimension(10,10);
}
}
}
This is the timer section:
timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
for (int x = 0; x < cellGrid.length; x++)
for (int y = 0; y < cellGrid[x].length; y++){
cellGrid[x][y].setColor();
currentGrid[x][y] = newGrid[x][y];
}
//Display processing for next frame
for (int x = 0; x < currentGrid.length; x++)
for (int y = 0; y < currentGrid[x].length; y++){
int b = checkNeighbors(y,x);
if (b > 4 || b < 2)
newGrid[x][y] = black;
else newGrid[x][y] = white;
}
if(!run) timer.stop();
}
});
I'm planning on adding more features later to give the user more control over various variables such as the grid size and iteration speed, but I want to get the core functionality of the display working. I'm fairly sure the issue is in how I'm using the Timer class since it's the timing that's broken.
My first question is: Am I using the Timer class right? If so, then what is the issue? If not, how should I be using it?
Update
That's a good idea, MadProgrammer, and it's good to know I'm using Timer correctly. I realized that the part where it was "running" was actually how long it took each individual cell to update its color, so really my program is just absurdly slow and inefficient as it is now.
Here's my idea to improve the speed and efficiency. Mainly, I would use the timer delay to process the output of the next iteration, then the next time the timer "fires" I would change a "tick" variable that each cell would use as their signal to change color, as suggested. To accomplish this, I've added a timer to each cell (how good/bad an idea is this?) that kill time for a bit, then, in a blocking while loop, wait to see that the internal "tick" is equivalent to the global "tick" and immediately change color when that happens.
The end result is that it freezes as soon as it starts.
This is the timer I added to the Cell class constructor:
c_timer = new Timer(500, new ActionListener(){
public void actionPerformed(ActionEvent e){
c_timer.stop();
while (c_tick != tick);
setBackground(currentGrid[posx][posy]);
c_tick = 1 - c_tick;
if(run) timer.restart();
}
});
c_timer.start();
And this is how I've modified the global timer:
timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
currentGrid[y][x] = newGrid[y][x];
tick = 1 - tick;
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++){
if (b[y][x] > 6 || b[y][x] < 1) newGrid[y][x] = white;
else newGrid[y][x] = black;
}
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
b[y][x] = checkNeighbors(x,y);
if(!run) timer.stop();
}
});
Other than these changes, I removed the setColor() method in the Cell class. Can anyone point out the mistake that I'm making?
UPDATE 2
I should have updated earlier, but simply put, I discovered this is entirely the wrong way to do it. Instead of making a panel full of components and changing their backgrounds, you should instead just paint the panel with a grid:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for (int h = 0; h < board_size.height; h++){
for (int w = 0; w < board_size.width; w++){
try{
if (grid[h][w] == BLACK)
g.setColor(BLACK);
else g.setColor(WHITE);
g.fillRect(h * cell_size, w * cell_size, cell_size, cell_size);
} catch (ConcurrentModificationException cme){}
}
}
}
On each timer "tick" you first repaint the grid, then you process the next iteration to be painted on the next tick. Far more efficient, and updates instantly.
My I used a modified JPanel as the main grid component which implements an ActionListener to process every action the user performs on the rest of the gui as well as each timer tick:
public void actionPerformed(ActionEvent e) {
//Timer tick processing: count surrounding black cells, define next iteration
//using current rule set, update master grid
if (e.getSource().equals(timer)){
//Processing for each tick
}
else if(e.getSource()...
//Process events dispached by other components in gui
}
Of course, you'd have to set the board panel as the action listener for the timer.
Your usage of the Timer class in the first part of the question indeed looks correct. What is happening with a java.swing.Timer is that the ActionListener is triggered on the Event Dispatch Thread at specific intervals, specified with the delay parameter.
This also means that the code you put in the ActionListener should execute quickly. While your ActionListener code is executing, the UI cannot update as the UI thread (the Event Dispatch Thread) is occupied executing the ActionListener code. This is clearly documented in the javadoc of that class.
Although all Timers perform their waiting using a single, shared thread (created by the first Timer object that executes), the action event handlers for Timers execute on another thread -- the event-dispatching thread. This means that the action handlers for Timers can safely perform operations on Swing components. However, it also means that the handlers must execute quickly to keep the GUI responsive.
This is exactly what you encountered in your first update
new Timer(500, new ActionListener(){
public void actionPerformed(ActionEvent e){
//...
while (c_tick != tick){}
//...
}
});
With the while loop here you are blocking the Event Dispatch Thread. The c_tick != tick check will never change as the variables involved are only adjusted on the EDT, and you are blocking it with the loop.
Your second update seems to suggest everything is working now by switching from a panel. There are however two weird looking things:
The catch ConcurrentModificationException cme code block. In the code you posted I cannot immediately spot where you would encounter a ConcurrentModificationException. Remember that Swing is single-threaded. All actions which could interact with Swing components should be executed on the EDT, making the chance on encountering a ConcurrentModificationException a lot smaller compared to a multi-threaded application.
You stated
Of course, you'd have to set the board panel as the action listener for the timer
This seems untrue. Whatever ActionListener attached to the Timer needs to swap the current grid and the next grid, and calculate the next grid. Once the next grid is calculated, it needs to schedule a repaint of the grid panel. Whether or not this ActionListener is an anonymous/inner/separate class or the grid panel itself is irrelevant (at least functionality wise, design wise I would never opt to let the grid panel be a listener).
Side note: when you need to swap the current and new grid you use the following code
for (int y = 0; y < height; y++){
for (int x = 0; x < width; x++){
currentGrid[y][x] = newGrid[y][x];
}
}
If you still have performance problems, you can try using System.arrayCopy which is probably much faster then looping over the array manually.
Here is a game of life that updates the screen every half second in a conventional Java Swing manner.
It would be pretty simple to add controls for setting grid size and update rate and also an edit mode where the animation stops and cells can be set with the mouse. To change the update rate, call lifePane.run(newUpdateInterval) or lifePane.run(0) to pause. Call lifePane.setGenSize(width, height) to change the grid.
The main value in using a separate thread for the generation computation (as has been suggested, but I haven't done here) is that the animation will continue while you manipulate the GUI. For example if you use a slider to control speed, the animation will not pause is it will ifgenerations are computed in the UI thread.
Addition For grins, I added controls and used a java.utils.timer rather than Swing timer to get the effect of an extra thread for the rendering in this Gist.
But if you don't mind the pause while manipulating "mouse down" GUI items, single threading is fine. My old laptop runs a generation size of 1000x1000 at 20 updates per second in the Swing event thread with the GUI still behaving very nicely.
The method update() fills in the next generation from the current one and then swaps buffers. The override of paintComponent just draws the current generation. With this combination, all the timer needs to do is update and repaint.
Other conventions that may be useful to you are the method of handling window resizing and organizing the neighbor computation. Knowing good idioms helps avoid verbose code.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class Life {
protected LifePane lifePane;
public static class LifePane extends JComponent {
private int rows, cols;
private byte[][] thisGen, nextGen;
private Timer timer;
public LifePane(int rows, int cols) {
setGenSize(rows, cols);
}
public final void setGenSize(int rows, int cols) {
this.rows = rows;
this.cols = cols;
thisGen = new byte[rows][cols];
nextGen = new byte[rows][cols];
Random gen = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
thisGen[i][j] = toByte(gen.nextBoolean());
}
}
}
#Override
protected void paintComponent(Graphics g) {
int width = getWidth();
int height = getHeight();
// Clear the background.
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
// Set the 1-valued cells black.
g.setColor(Color.BLACK);
int y0 = 0;
for (int i = 1; i < rows; i++) {
int y1 = i * height / (rows - 1);
int x0 = 0;
for (int j = 1; j < cols; j++) {
int x1 = j * width / (cols - 1);
if (thisGen[i][j] != 0) {
g.fillRect(x0, y0, x1 - x0, y1 - y0);
}
x0 = x1;
}
y0 = y1;
}
}
/**
* Make the next generation current.
*/
private void swapGens() {
byte [][] tmp = thisGen;
thisGen = nextGen;
nextGen = tmp;
}
private static byte toByte(boolean booleanVal) {
return booleanVal ? (byte) 1 : (byte) 0;
}
// Implementation of Conway's Game of Life rules.
private void updateCell(int x0, int x, int x1, int y0, int y, int y1) {
int n = thisGen[y0][x0] + thisGen[y0][x] + thisGen[y0][x1] +
thisGen[y] [x0] + thisGen[y] [x1] +
thisGen[y1][x0] + thisGen[y1][x] + thisGen[y1][x1];
nextGen[y][x] =
(thisGen[y][x] == 0) ? toByte(n == 3) : toByte(n >> 1 == 1);
}
private void updateRow(int y0, int y, int y1) {
updateCell(cols - 1, 0, 1, y0, y, y1);
for (int j = 1; j < cols - 1; ++j) {
updateCell(j - 1, j, j + 1, y0, y, y1);
}
updateCell(cols - 2, cols - 1, 0, y0, y, y1);
}
// Update the grid as a toroid and swap buffers.
public void update() {
updateRow(rows - 1, 0, 1);
for (int i = 1; i < rows - 1; i++) {
updateRow(i - 1, i, i + 1);
}
updateRow(rows - 2, rows - 1, 0);
swapGens();
}
/**
* Run the life instance with given update interval.
*
* #param updateInterval interval in milliseconds, <= 0 to stop
* #return this
*/
public LifePane run(int updateInterval) {
if (timer != null) {
timer.stop();
timer = null;
}
if (updateInterval > 0) {
timer = new Timer(updateInterval, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
});
timer.start();
}
return this;
}
}
public void run(int width, int height, int updateInterval) {
JFrame frame = new JFrame("Life");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
lifePane = new LifePane(width, height).run(updateInterval);
frame.setContentPane(lifePane);
frame.setPreferredSize(new Dimension(1024, 800));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Life().run(100, 100, 500);
}
});
}
}
I'm planning on adding more features later to give the user more control over various variables such as the grid size and iteration speed, but I want to get the core functionality of the display working. I'm fairly sure the issue is in how I'm using the Timer class since it's the timing that's broken.
This is a good strategy, the program runs well, but it could be more efficient and scalable.
For example, I recommend using a custom SwingWorker class to execute your computation, and then send a message back to the UI.
Here is an example of how I would create this in a SwingWorker.
Here is addition information available from the Oracle resources site: http://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class CA_Driver extends JFrame
{
private JPanel gridPanel, buttonPanel;
private JButton start_pause, pause;
// private static Timer timer;
private Color black = Color.black;
private Color white = Color.white;
static Color[][] currentGrid, newGrid;
static Cell[][] cellGrid;
static boolean stop;
static int height = 20, width = 30, state;
boolean run;
private synchronized boolean getRun()
{
return run;
}
private synchronized void setRun(boolean run)
{
this.run = run;
}
/**
* http://docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html
*
*/
SwingWorker worker = createNewWorker();
private SwingWorker createNewWorker()
{
return
new SwingWorker<Void, Void>()
{
protected Void doInBackground() throws Exception
{
while(getRun())
{
for (int x = 0; x < cellGrid.length; x++)
{
for (int y = 0; y < cellGrid[x].length; y++)
{
cellGrid[x][y].setColor();
currentGrid[x][y] = newGrid[x][y];
}
}
//Display processing for next frame
for (int x = 0; x < currentGrid.length; x++)
{
for (int y = 0; y < currentGrid[x].length; y++)
{
int b = checkNeighbors(y,x);
if (b > 4 || b < 2)
{
newGrid[x][y] = black;
}
else
{
newGrid[x][y] = white;
}
}
}
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
return null;
}
#Override
protected void done()
{
super.done();
}
};
}
public CA_Driver()
{
stop = false;
setRun(false);
currentGrid = new Color[height][width];
newGrid = new Color[height][width];
cellGrid = new Cell[height][width];
//Initialize grid values
for(int x = 0 ; x < currentGrid.length ; x++)
for(int y = 0 ; y < currentGrid[x].length ; y++)
{
int z = (int) (Math.random() * 2);
if(z == 0)
currentGrid[x][y] = newGrid[x][y] = white;
else
currentGrid[x][y] = newGrid[x][y] = black;
}
//Create grid panel
gridPanel = new JPanel();
gridPanel.setLayout(new GridLayout(height, width));
//Populate grid
for(int x = 0 ; x < newGrid.length ; x++)
for(int y = 0 ; y < newGrid[x].length ; y++)
{
cellGrid[x][y] = new Cell(x, y);
cellGrid[x][y].setBackground(newGrid[x][y]);
int z = (int) Math.random();
if(z == 0)
cellGrid[x][y].setBackground(black);
else
cellGrid[x][y].setBackground(currentGrid[x][y]);
gridPanel.add(cellGrid[x][y]);
}
//Create buttons
state = 0;
start_pause = new JButton();
start_pause.setText("Start");
start_pause.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
if(state == 0)
{
start_pause.setText("Pause");
setRun(true);
worker = createNewWorker();
worker.execute();
// timer.start();
state += 1;
}
else
{
start_pause.setText("Start");
setRun(false);
// timer.stop();
state -= 1;
}
}
});
buttonPanel = new JPanel(new BorderLayout());
buttonPanel.add(start_pause, BorderLayout.NORTH);
// buttonPanel.add(pause, BorderLayout.EAST);
//Initialize and display frame
this.add(gridPanel, BorderLayout.NORTH);
this.add(buttonPanel, BorderLayout.SOUTH);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
//this.setSize(500, 500);
pack();
this.setVisible(true);
worker.execute();
/*
//Initialize timer
timer = new Timer(1000, new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
for(int x = 0 ; x < cellGrid.length ; x++)
for(int y = 0 ; y < cellGrid[x].length ; y++)
{
cellGrid[x][y].setColor();
currentGrid[x][y] = newGrid[x][y];
}
//Display processing for next frame
for(int x = 0 ; x < currentGrid.length ; x++)
for(int y = 0 ; y < currentGrid[x].length ; y++)
{
int b = checkNeighbors(y, x);
if(b > 4 || b < 2)
newGrid[x][y] = black;
else
newGrid[x][y] = white;
}
if(!getRun())
timer.stop();
}
});
*/
}
public static void main(String[] args)
{
new CA_Driver();
}
private int checkNeighbors(int w, int h)
{
int b = 0;
//Top Left
if((w != 0) && (h != 0) && (currentGrid[h - 1][w - 1] == black))
b++;
//Top Middle
if((h != 0) && (currentGrid[h - 1][w] == black))
b++;
//Top Right
if((w != width - 1) && (h != 0) && (currentGrid[h - 1][w + 1] == black))
b++;
//Middle Left
if((w != 0) && (currentGrid[h][w - 1] == black))
b++;
//Middle Right
if((w != width - 1) && (currentGrid[h][w + 1] == black))
b++;
//Bottom left
if((w != 0) && (h != height - 1) && (currentGrid[h + 1][w - 1] == black))
b++;
//Bottom Middle
if((h != height - 1) && (currentGrid[h + 1][w] == black))
b++;
//Bottom Right
if((w != width - 1) && (h != height - 1) &&
(currentGrid[h + 1][w + 1] == black))
b++;
return b;
}
private class Cell extends JPanel
{
private Color c;
private int posx, posy;
public Cell(int x, int y)
{
posx = x;
posy = y;
}
public Point getLocation()
{
return new Point(posx, posy);
}
public void setColor()
{
c = newGrid[posx][posy];
setBackground(c);
}
public Dimension getPreferredSize()
{
return new Dimension(10, 10);
}
}
}