So I am new to Swing and JFrames and such so I kind of struggle with this subject. I'm trying to create a Game of Life application and visual showing it. They underlaying "maths" is already done but I have no clue on how to visually show it. What I am looking for is some kind of grid which I can colour in. This is what I'm talking about: http://en.wikipedia.org/wiki/Conway's_Game_of_Life
You can create a grid for your scope using only standard java swing library.
All you need is drawLine method for the grid layout and fillOvall for paint some cells.
This is a full and running example :
import javax.swing.*;
public class MyGrid extends JApplet {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Grid Panel Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new MyGrid();
applet.init();
frame.getContentPane().add(applet);
frame.pack();
frame.setVisible(true);
}//end main method
public void init() {
JPanel panel = new GridPanel();
getContentPane().add(panel);
}//end init method
class GridPanel extends JPanel {
int n = 30; //Number of cells of my squeare grid
public GridPanel() {
setPreferredSize(new Dimension(480, 480));
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
g2D.setColor(Color.lightGray);
//Set the cell dimension
int p=0;
int c=16;
int len = c*n;
//Draw the grid
for (int i = 0; i <= n; i++) {
g2D.drawLine(0, p, len, p);
g2D.drawLine(p, 0, p, len);
p += c;
}
//You can paint the (i,j) cell with another color in this way
int i=10;
int j=20;
g2D.setColor(Color.GREEN);
int x = i*c;
int y = j*c;
g2D.fillOval(x, y, c, c);
}//end paintComponent
}//end inner class GridPanel
}//end class
Copy it in a file name MyGrig.java
Then compile it javac MyGrid.java
and finally java MyGrid
A possible solution is this. I create a new class ChangeCellsClass for the logic of painting cells, and i call it's method every second in the appropriate event.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class MyGrid extends JApplet {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Grid Panel Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new MyGrid();
applet.init();
frame.getContentPane().add(applet);
frame.pack();
frame.setVisible(true);
}//end main method
public void init() {
JPanel panel = new GridPanel();
getContentPane().add(panel);
}//end init method
class GridPanel extends JPanel implements ActionListener {
int n = 30; //Number of cells of my squeare grid
boolean[][] cells; //Grid data model
public GridPanel() {
setPreferredSize(new Dimension(480, 480));
setBackground(Color.BLACK);
//Initialize data model
cells = new boolean[n][n];
//Every seconds fire event for update the stste
Timer timer = new Timer(1000, this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
g2D.setColor(Color.lightGray);
//Set the cell dimension
int p=0;
int c=16;
int len = c*n;
//Draw the grid
for (int i = 0; i <= n; i++) {
g2D.drawLine(0, p, len, p);
g2D.drawLine(p, 0, p, len);
p += c;
}
//Draw active cells
g2D.setColor(Color.GREEN);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (cells[i][j]) {
int x = i*c;
int y = j*c;
g2D.fillOval(x, y, c, c);
}
}
}
}//end paintComponent
//Action performed Event
public void actionPerformed(ActionEvent e) {
ChangeCellsClass ccc = new ChangeCellsClass();
cells = ccc.setCells(cells);
repaint();
}//end actionPerformed
}//end inner class GridPanel
}//end class
//This is your class for compute active cells. ChangeCellsClass.java
public class ChangeCellsClass {
public ChangeCellsClass() {
//Some initialization code ....
}//end constructor
public boolean[][] setCells(boolean[][] cells) {
int n = 30; //you may obtain this value dinamically from cells matrix
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cells[i][j] = Math.random() < 0.1;
}
}
return cells;
}//end method
}//end class
Related
The printout of the array lifegrid2 just gives all zeros. I tested the lifegrid array in MyPanel and that is populating, but the values are pulling through as zeros. I checked by putting some values in lifegrid2 and they are being wiped, so it is pulling through from MyPanel, but only zeros. There are no errors being reported.
I have made a small test program with a 2d array which does pull values through.
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import java.awt.*;
import java.awt.event.*;
public class SwingPaintDemo3 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Swing Paint Demo");
f.setPreferredSize(new Dimension(1280,800));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
JPanel subPanel = new JPanel();
JButton start = new JButton("START");
subPanel.add(start);
start.setPreferredSize(new Dimension(100,50));
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae1) {
System.out.println("START");
int [][][] lifegrid2 = new int [12][12][2];
int temp;
for (int i=0; i<12; i++) {
for (int j=0; j<12; j++) {
**MyPanel obj = new MyPanel();
temp = obj.lifegrid [i][j][0];
lifegrid2 [i][j][0] = temp;**
if (j<11)
{System.out.print(lifegrid2 [j] [i] [0]);}
else
{System.out.println(lifegrid2 [j] [i] [0]);}}}
}
});
f.add(subPanel, BorderLayout.EAST);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
class MyPanel extends JPanel {
public int [][][] lifegrid = new int [12][12][2];
private int squareX = 1280;
private int squareY = 800;
private int gridX, gridY ;
public MyPanel() {
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
squareX = e.getX();
squareY = e.getY();
if ((squareX>50 & squareX <550) & (squareY>50 & squareY <550) ){
gridX =(squareX-50)/50+1;
gridY =(squareY-50)/50+1;
squareX = (squareX -50)/50 * 50 + 50;
squareY = (squareY -50)/50 * 50 + 50;
System.out.println(gridX + " " + gridY);
lifegrid [gridX] [gridY] [0] = 1;
repaint(squareX,squareY,50,50);}
else {
}
}
});
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,48,48);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,48,48);
}
}
I have made a small test program with a 2d array
int [][][] lifegrid2 = new int [12][12][2];
That is a 3D array.
A 2D array is defined as:
int [][] lifegrid2 = new int [12][12];
The logic to initialize the array belongs in the constructor of your class:
MyPanel()
{
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
lifegrid [i][j] = 0)
}
}
}
Then your paintComponent() method needs to iterate through the 2D grid and only paint the grids that have a value of 1.
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
if (lifegrid[i][j] = 1)
// paint the grid
}
}
}
}
Edit:
As best as I can tell you are trying to create a grid based game. When you click on a cell in the grid the cell turns red. The are two common ways to approach this:
Use components. In this approach you have a parent panel using a GridLayout and you add a child panel to each cell in the grid. You would also add your MouseListener to each child panel. When you click on the child panel you change the background of the panel to red.
Do custom painting. In this approach you have a single JPanel. This class keep a 2D Array for the "state" of each cell in the grid. You add a single MouseListener to the panel. When you click on the panel you determine which cell was clicked and then you update the state of that cell. In the paintComponent() method you iterate through the 2D Array and paint each cell where that state has changed.
Your approach seems to be some kind of hybrid between the two and is not working.
What the code should do is draw X randomized shapes with the click of a button. What I have so far is a subclass that creates the random shape to be placed inside the JPanels, but the issue is that the same shape is used in all panels, I need each shape to be randomized.
The subclass looks like this:
public class Shapes extends JPanel
{
Random rand = new Random();
private int x = 5;
private int y = 5;
private int diameter = 200;
private Color outline;
private Color internal;
private Color internal2;
private Color internal3;
public Shapes() {
this(new Random());
}
//randomizes colors
public Shapes(Random rand) {
outline = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
internal = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
internal2 = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
internal3 = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
}
{
super.paintComponent(g);
g.setColor(outline);
g.drawOval(x, y, diameter, diameter);
g.setColor(internal);
g.fillOval(x+2, y+2, diameter-4, diameter-4);
g.setColor(internal2);
g.fillOval(x+25, y+66, diameter/3, diameter/3);
g.fillOval(x+125, y+66, diameter/3, diameter/3);
g.setColor(internal3);
g.fillArc(x+55, y+105, diameter/3, diameter/3, 180, 180);
}
}
While the main class looks like so [currently set up to make 6 images]:
public class ShapeGrid extends JFrame implements ActionListener
{
private JButton button;
int i = 2;
int j = 3;
JPanel[][] panelHolder = new JPanel[i][j];
private Shapes shapes;
public static void main(String[] args)
{
ShapeGrid myGrid = new ShapeGrid();
myGrid.setSize(800, 800);
myGrid.createGUI();
myGrid.setVisible(true);
}
public ShapeGrid()
{
setLayout(new GridLayout(i,j, 5, 5));
for(int m = 0; m < i; m++) {
for(int n = 0; n < j; n++) {
panelHolder[m][n] = new JPanel();
add(panelHolder[m][n]);
}
}
}
private void createGUI()
{
shape = new Shapes();
setDefaultCloseOperation(EXIT_ON_CLOSE);
button = new JButton("Press me");
add(button);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent ae)
{
if (ae.getSource() == button) {
for(int m = 0; m < i; m++) {
for(int n = 0; n < j; n++) {
shape.paintComponent(panelHolder[m][n].getGraphics());
}
}
}
}
}
shape.paintComponent(panelHolder[m][n].getGraphics());
You should NEVER invoke paintCopmonent() directly and you should never use getGraphics(). Swing will determine when a component needs to be painted and Swing will pass the Graphics object to the paintComponent() method.
Once you follow the advice below there is no need for the "Press Me" button (or the above) because the Shapes will be created when the when the ShapeGrid class is created. And the Shapes will automatically be painted when the frame is made visible.
is that the same shape is used in all panels,
You only ever create a single Shape object. You need to create a Shape object for each grid. So in the constructor of the ShapeGrid you need to create one Shape object for each grid.
I suggest you should pass in the rows/columns you want for your grid (instead of hardcoding i/j in your class). So your ShapeGrid constructor code might be something like:
public ShapeGrid(int rows, columns)
{
setLayout(new GridLayout(rows, columns, 5, 5));
int drawShapes = rows * columns;
for(int i = 0; i < drawShapes; i++) {
add( new Shape() );
}
}
That's it. There is no need for the panel holder. You will now have uniques Smileys added to the frame.
Then in your main() method you do something like:
ShapeGrid myGrid = new ShapeGrid(2, 3);
Essentially I am trying to add a circle to a JPanel grid matrix (This is where my main problem lies).
When running the code below, once the new OvalComponent class is called to add the circle to a the (1,1) position in the grid, the class is read, but the paint component function is just skipped.
package Exercises;
import javax.swing.*;
import java.awt.*;
import java.io.FileNotFoundException;
/**
* Created by user on 4/1/2017.
*/
public class Mazes extends JPanel {
public static void main(String[] args) throws FileNotFoundException {
Mazes maze = new Mazes();
}
public Mazes() throws FileNotFoundException{
Boolean[][] maze = Exercise4.readMaze();
int row = maze.length;
JFrame f = new JFrame("Maze");
f.setLayout(new GridLayout(row, row));
JPanel[][] grid = new JPanel[row][row];
for (int i = 0; i < row; i++) {
for (int j = 0; j < row; j++) {
grid[i][j] = new JPanel();
grid[i][j].setOpaque(true);
if ((i==1&&j==1) || (i==row-1 && j==row-1))
grid[i][j].add(new OvalComponent());
if (maze[i][j].equals(false)){
grid[i][j].setBackground(Color.BLACK);}
else grid[i][j].setBackground(Color.WHITE);
f.add(grid[i][j]);
}
}
//f.add(new JButton("Reset"), BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
class OvalComponent extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillOval(4, 4, 10, 10);
}
}
OvalComponent has no definable size (defaults to 0x0), so while the component is been added it's been added with a size of 0x0 and Swing is clever enough to know that it doesn't need to paint it.
Override the component's getPreferredSize method and return an appropriate size
#Override
public Dimension getPreferredSize() {
return new Dimension(18, 18);
}
as an example
The panel doesn't fit in the frame, and when I change the size of the frame a new panel is painted. I want the panel to fit and also to change the size on the frame without painting a new panel.
Here is the code:
import java.awt.*;
import javax.swing.*;
public class ColorGrid extends JPanel {
int length=200;
int width=200;
double stokastik;
public ColorGrid(int x,int y) {
setSize(200,200);
width=18*x;
length=18*y;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int row=0; row <=length;row+=20) {
for(int col=0; col <=width;col+=20) {
stokastik= Math.random();
if(stokastik < 0.25){
g.setColor(Color.YELLOW);
}
else if (stokastik < 0.5) {
g.setColor(Color.BLUE);
}
else if (stokastik < 0.75) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(row, col, 18, 18);
}
}
}
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setBounds(300,300,300,300);
ColorGrid grid = new ColorGrid(10,10);
frame.add(grid);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
}
Your code is confusing because you call setBounds/setSize, but eventually, you call pack() which will just resize everything according to preferred size of components.
The proper way to go is to override getPreferredSize() in your custom component. By all means, avoid calling setSize/setBounds/setLocation. This is the job of the LayoutManager.
Regarding the repaint of the panel, you don't have a choice. A panel can get repainted many times independently of your will. So the only way to avoid the change of colors when the repaint occurs, is to pre-calculate the colors upfront and then only iterate over the same colors when performing the custom painting.
Small demo code illustrating this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ColorGrid extends JPanel {
double stokastik;
private int width;
private int length;
private Dimension preferredSize;
private Color[][] colors;
public ColorGrid(int x, int y) {
width = 20 * x;
length = 20 * y;
preferredSize = new Dimension(width, length);
colors = new Color[x][y];
for (int row = 0; row < x; row++) {
for (int col = 0; col < y; col++) {
stokastik = Math.random();
if (stokastik < 0.25) {
colors[row][col] = (Color.YELLOW);
} else if (stokastik < 0.5) {
colors[row][col] = (Color.BLUE);
} else if (stokastik < 0.75) {
colors[row][col] = (Color.GREEN);
} else {
colors[row][col] = (Color.RED);
}
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (int row = 0; row < colors.length; row++) {
for (int col = 0; col < colors[row].length; col++) {
g.setColor(colors[row][col]);
g.fillRect(row * 20, col * 20, 18, 18);
}
}
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ColorGrid grid = new ColorGrid(10, 10);
frame.add(grid);
frame.pack();
frame.setVisible(true);
}
});
}
}
In your constructor set the preferred size.
public ColorGrid(int x, int y) {
setSize(200, 200);
setPreferredSize(new Dimension(200, 200));
width = 18 * x;
length = 18 * y;
}
Then it will show correctly on initial load..
As mentioned by another answer, also have your length and width defined proportionally.
I need help with drawing the grids to the GUI as well as the program later letting me change the colour of the boxes drawn. I know i will have to use paintComponent(Graphics g), but i have no idea how or where.
So here is a copy of the code i have got so far ( even though i have been told it can be quite daunting just being given code i think it is the best way for people to help and not just do it for me). From the top it sets values, creates the GUI, calls the GUI, fills a 2d array with boxes( i think). Then in the Boxes class setting values the boxes class will need, then the start of how to draw them (didn't know how to work it out), then some seta methods for the x and y coordinates.
what i would like you to do is show how to have the boxes be drawn to the Jpanel, to make a grid and then to show me how to change the colour to different shades of blue, depending on a external value.
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
Boxes[][] Boxs;
int BoxesX;
int BoxesY;
NewGrid() {
buildtheGUI();
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public void buildtheGUI() {
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
new NewGrid();
}
public void addboxes() {
Boxs = new Boxes[panel.getWidth() / 10][panel.getHeight() / 10];
for (int i = 0; i < panel.getWidth() / 10; i++) {
for (int j = 0; j < panel.getHeight() / 10; j++) {
Boxs[i][j] = new Boxes();
Boxs[i][j].setx(i * (panel.getWidth() / 10));
Boxs[i][j].sety(j * (panel.getHeight() / 10));
Boxs[i][j].draw(null);
}
}
}
}
public class Boxes extends JPanel {
int x;
int y;
int width = 10;
int hieight = 10;
Color colour = Color.BLACK;
public void draw(Graphics g) {
g.setColor(colour);
g.fillRect(x, y, width, hieight);
}
public void setx(int i ){
x = i;
}
public void sety(int i ){
y = i;
}
}
I can't comment something, to try to make things easier,
I code there box.putClientProperty(unique_identifier, value_for_identifier), you can to multiple this method as you want
from every Swing Listener you can to get this and proper coordinated defined in putClientProperty
.
JComponent comp = event.getComponent();
String strRow = (String) comp.getClientProperty("row");
String strColumn = (String) comp.getClientProperty("column");
simple code
import java.awt.*;
import java.awt.Graphics;
import java.util.*;
import javax.swing.*;
public class NewGrid {
private int row = 10;
private int column = 10;
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private NewGrid() {
addboxes();
panel.setLayout(new GridLayout(row, column));
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private void addboxes() {
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
Boxes box = new Boxes();
box.putClientProperty("row", row);
box.putClientProperty("column", column);
panel.add(box);
}
}
}
public static void main(String[] args) {
Runnable doRun = new Runnable() {
#Override
public void run() {
new NewGrid();
}
};
SwingUtilities.invokeLater(doRun);
}
}
class Boxes extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(20, 20);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(20, 20);
}
#Override
public void paintComponent(Graphics g) {
int margin = 2;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2,
dim.height - margin * 2);
}
}