I am trying two draw a 2D array(dynamic) of random boxes with different colors,
this is the code:
Main.java
public class Main {
public static void main(String[] args) {
CustomPanel f = new CustomPanel (4, 5);
JFrame frame = new JFrame("Testing");
frame.add(f);
frame.setSize(1000, 1000);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
CustomPanel.java:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class CustomPanel extends JPanel {
Drawable [][]boxes;
public CustomPanel (int rows, int cols)
{
this.setLayout(null);
boxes = new Drawable[rows][cols];
Random rand = new Random();
for(int i = 0 ; i < rows ; i ++)
{
for(int j = 0 ; j < cols ; j++)
{
switch(rand.nextInt(3))
{
case 0:
boxes [i][j] = new Box1();
break;
case 1:
boxes [i][j] = new Box2();
break;
case 2:
boxes [i][j] = new Box3();
break;
}
}
}
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
Rectangle t = g.getClipBounds();
int box_width = t.width/ this.boxes[0].length;
int box_heigt = t.height/ this.boxes.length;
for(int i = 0 ; i < this.boxes.length; i ++)
{
for(int j = 0 ; j < this.boxes[0].length; j++)
{
System.out.println("" + i + ":" + j);
boxes [i][j].draw(i * box_width, j * box_heigt, box_width, box_heigt, g);
}
}
}
}
Drawable.java:
import java.awt.Graphics;
public interface Drawable {
public abstract void draw(int x, int y, int width, int height, Graphics g);
}
Box1(Box2, Box3 are the same, just different colors):
import java.awt.Color;
import java.awt.Graphics;
public class Box1 implements Drawable{
public Box1 () { //default constructor
}
#Override
public void draw(int x, int y, int width, int height, Graphics g) {
g.setColor(Color.CYAN);
g.fillRect(x, y, width, height);
}
}
The problem is that some of the boxes do not appear at the panel at all(altought I do iterate over both rows and columns).
I debugged it but could not find out why it happens(it might be silly - i know)
Box1(Box2, Box3 are the same, just different colors):
Don't create separate classes, just pass the Color as a parameter.
do you mean at paintComponent ? how? I guess this.getParent().getSize().width ?
Yes, paintComponent().
No, you don't get the parent. You are doing custom painting on a JPanel. You want the width/height of the panel using the methods I suggested in my comment.
The problem is that some of the boxes do not appear at the panel at all
You have your x/y values reversed when you paint each Box. The "i" variable represents the rows (or the y value) and the "j" variable represents the columns (or the x value).
So your logic should b:
for(int i = 0 ; i < this.boxes.length; i ++)
{
for(int j = 0 ; j < this.boxes[0].length; j++)
{
//boxes [i][j].draw(i * box_width, j * box_heigt, box_width, box_heigt, g);
boxes [i][j].draw(j * box_width, i * box_heigt, box_width, box_heigt, g);
}
}
instead of using the Array length property to control the rows/columns, why not just save the row/column parameters as variable in your class which might help make your code easier to read.
Related
I am attempting to draw a checkerboard pattern in java using nested for loops, but I am having trouble doing it with two different colors. I know this question has been asked before, but it hasn't been asked with two different colors on the board that are not just using a background color. I plan on using the individual squares as an array to hold checker positions, so I do need each individual square made. Would it be better to drop the ice of a nested for loop to create each square, or should i stick with that shortcut? And if I were to stick with it, how would the nested loop be formatted (one for each color)?
When creating checker tiles, I would pass in an int for the x coordinate, and y coordinate such as:
import java.awt.Color;
import java.awt.Graphics;
public class CheckerTile {
public static final int WIDTH = 100; //width of each tile
public static final int HEIGHT = 100; //height of each tile, most likely same as width so its a square
public static int currentId = 0; //variable to reference unique id for each tile
private int id; //current id of tile
private int x; //x coordinate
private int y; //y coordinate
private int width; //width of tile
private int height; //height of tile
//Default constructor to take x and y coordinate
public CheckerTile( int x, int y ) {
this.id = currentId++;
this.x = x;
this.y = y;
width = WIDTH;
height = HEIGHT;
}
public int getId()
{
return id;
}
//draws the tile on the panel.
public void draw(Graphics g)
{
//if the checkerTile's id is divisible by 2, draw it red, otherwise draw it black.
g.setColor( id % 2 == 0 ? Color.RED : Color.black);
g.fillRect(x, y, width, height);
}
}
That way we have a way to draw the tile on the board. Now, when creating each object, we increment a currentId variable so that we can color each one individually using the modulus operator later.
I am assuming you are using Swing so I decided to add a draw(Graphics g) method so when repainting in java it would use that Graphics object. If you are using a different library, then you will have to do some research in to how to draw it on the board.
Now in your JPanel, it would look something like this:
//Creates the JPanel, which needs to be added to JFrame object in main
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CheckerBoard extends JPanel {
CheckerTile[][] checkerTiles; //2-dimension array of checkerTiles
public CheckerBoard() {
super();
this.setSize(800,800);
checkerTiles = new CheckerTile[9][9];
//This creates the checkerTiles.
for(int i = 0; i < 9; i++)
{
for( int j = 0; j < 9; j++)
{
checkerTiles[i][j] = new CheckerTile( j * CheckerTile.WIDTH, i * CheckerTile.HEIGHT );
}
}
this.setVisible(true);
//Repaint right away to show results.
repaint();
}
//We need to override this to paint the tiles on the board.
#Override
public void paintComponent(Graphics g)
{
for(int i = 0; i < checkerTiles.length; i++)
{
for(int j = 0; j < checkerTiles[i].length; j++)
{
//call the draw method on each tile.
checkerTiles[i][j].draw(g);
}
}
}
//A demo of adding the panel to a frame and showing the tiles.
public static void main(String[] args)
{
//Create the JFrame and add the CheckerBoard we made to it.
JFrame frame = new JFrame();
frame.setSize(800,800);
frame.setLayout(new BorderLayout());
frame.add(new CheckerBoard(), BorderLayout.CENTER);
frame.setVisible(true);
}
}
I have a Java Swing assignment with the following objectives:
When the program starts, it draws 20 unfilled circles, with radius and location of each determined at random.
If the perimeter line of a circle does NOT intersect any other circle, draw the outline of the circle in RED. If it does intersect at least one other circle, draw it in BLACK.
Add a JButton that, each time it is pressed, creates a new set of circles as described above.
I've completed objectives #1 and #3 above, but I'm stumped on objective #2.
Before I present the code, let me give my understanding of the math behind it. There are two ways a circle can NOT intersect another circle:
The circles are too far apart to share a perimeter point, i.e. the distance between their centers is greater than the sum of their radii (d > r1 + r2). Example.
One circle is completely inside another circle, and their perimeters do not touch, i.e. the distance between their centers is less than the difference between their radii (d < |r1 - r2|). Example.
What I've got so far:
To compare circles, they must be specified before they are drawn, so I used a for-loop to store 20 values in arrays for the center coordinates (int[] x, int[] y) and the radius (double[] radius).
Next, I used nested for-loops to iterate through the array and compare two circles, except when a circle is compared with itself (index j = index k). If the circles intersect, g.setColor(Color.RED). If not, g.setColor(Color.BLACK).
When I execute my code, the circles without any overlap are properly colored red. However, some of the overlapping circles are colored red as well. I assume that they were non-overlapping at the time they were drawn, but were intersected thereafter. How do I fix the code to account for this discrepancy in time? (Problem area located near the bottom, in IntersectingCircles class)
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JButton;
public class ButtonFrame extends JFrame
{
private final JButton resetButton = new JButton("Reset");
public ButtonFrame()
{
super("Drawing Random Circles");
setLayout(new BorderLayout());
IntersectingCircles intersectingCircles = new IntersectingCircles();
this.add(intersectingCircles, BorderLayout.CENTER);
this.add(resetButton, BorderLayout.SOUTH);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(1400, 1400);
ButtonHandler handler = new ButtonHandler();
resetButton.addActionListener(handler);
}
private class ButtonHandler implements ActionListener
{
#Override
public void actionPerformed(ActionEvent event)
{
reset();
}
}
public static void main(String[] args)
{
ButtonFrame buttonFrame = new ButtonFrame();
buttonFrame.setVisible(true);
}
public void reset()
{
ButtonFrame buttonFrame = new ButtonFrame();
buttonFrame.setVisible(true);
}
}
class IntersectingCircles extends JPanel
{
private static final JButton resetButton = new JButton("Reset Circles");
private static final JFrame frame = new JFrame("Intersecting Circles");
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.WHITE);
int[] x = new int[20];
int[] y = new int[20];
int[] diameter = new int[20];
double[] radius = new double[20];
for (int i = 0; i < 20; i++)
{
int xCoord = (int)(Math.random() * 600);
int yCoord = (int)(Math.random() * 600);
int circleSize = (int)(Math.random() * 550);
x[i] = xCoord;
y[i] = yCoord;
diameter[i] = circleSize;
radius[i] = circleSize / 2.0;
}
for (int j = 0; j < 20; j++)
{
for (int k = 0; k < 20; k++)
{
if (k != j)
{
if (((Math.sqrt((x[k] - x[j]) * (x[k] - x[j]) + (y[k] - y[j])
* (y[k] - y[j]))) > (radius[j] + radius[k])) ||
((Math.sqrt((x[k] - x[j]) * (x[k] - x[j]) + (y[k] - y[j])
* (y[k] - y[j]))) < (Math.abs(radius[j] - radius[k]))))
g.setColor(Color.RED);
else
g.setColor(Color.BLACK);
g.drawOval(x[j], y[j], diameter[j], diameter[j]);
}
else
continue;
}
}
}
}
You have logic mistake in if statement inside the cycle - you can set black color then revert to red for some other pair circle. Possible solution draft:
for (int j = 0; j < 20; j++)
{
g.setColor(Color.RED); //set non-intersect state
for (int k = j + 1; k < 20; k++) //avoid excessive work
{
if (intersect test)
{
g.setColor(Color.BLACK);
break; //can stop here
};
g.drawOval(x[j], y[j], diameter[j], diameter[j]);
}
}
So am working on a School Project, and I want to draw a game board made out of Rectangles which are saved in an array. I managed to do that, but only the last drawn Rectangle Stays on the Panel. I'm really desperate and i don't know where my mistake is.
The Field is a 4x5 field. The Coordinates saved in the Tile Class:
the first two represent the upper left Corner
the last two represent the bottom right corner of it
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class quoVadis{
public static void main(String[] args) {
new Frame();
}
}
class Tile {
Random rGen = new Random();
int sX,sY,eX,eY;
Color farbe;
public Tile(int sX, int sY,int eX,int eY){
this.sX = sX;
this.sY = sY;
this.eX = eX;
this.eY = eY;
farbe = new Color(rGen.nextInt(156)+100,rGen.nextInt(156)+100,rGen.nextInt(156)+100);
}
}
class Frame extends JFrame{
private Game game;
final int GAMESIZE = 400;
final int PANELSIZE = GAMESIZE/5;
public Frame() {
super("Quo Vadis");
this.setSize(GAMESIZE, GAMESIZE*5/4);
this.setLocation(50, 50);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game = new Game(GAMESIZE, PANELSIZE);
game.setLayout(null);
game.setBackground(Color.WHITE);
this.getContentPane().add(game);
this.setVisible(true);
}
}
class Game extends JPanel{
int GAMESIZE;
int PANELSIZE;
private Tile field[][]=new Tile[4][5];
Random rGen = new Random(4711);
Tile stein;
public Game(int g, int p) {
GAMESIZE = g;
PANELSIZE = p;
// The Mistake has to be in this following Part:
int idx=0;
for(Tile i:levels){
for(int j = i.sX; j <= i.eX; j++){
for(int k = i.sY; k <= i.eY; k++){
field[j][k] = levels[idx];
}
}
idx++;
}
for(int k = 0; k <= 4; k++){
for(int j = 0; j <= 3; j++){
if(field[j][k]==null)continue;
stein=field[j][k];
draw((field[j][k].sX * PANELSIZE) , (field[j][k].sY * PANELSIZE) , ((((field[j][k].eX-field[j][k].sX) + 1) * PANELSIZE) -1), ((((field[j][k].eY-field[j][k].sY)+ 1) * PANELSIZE) -1));
}
}
this.setVisible(true);
}
int rx, ry,rdx,rdy;
private void draw(int a, int b, int c, int d){
rx=a;
ry=b;
rdx=c;
rdy=d;
repaint(rx,ry,rdx,rdy);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(stein.farbe);
g.fillRect(rx, ry, rdx, rdy);
}
Tile[] levels = {
new Tile(1,0,2,1),
new Tile(0,0,0,1),
new Tile(3,0,3,1),
new Tile(0,2,0,3),
new Tile(1,2,2,2),
new Tile(3,2,3,3),
new Tile(0,4,0,4),
new Tile(1,3,1,3),
new Tile(2,3,2,3),
new Tile(3,4,3,4),
};
}
I already checked the Position of the Rectangles in numbers and they are correct in every way so they do not overlap or something like that.
Sorry for my bad english, it's not my primary language.
You need to draw each rectangle inside of your paintComponent method every time.
Currently you are calling your draw method for one rectangle then you call repaint and draw that single rectangle. paintComponent will redraw the entire panel each time it is called. This means that it will on preserve the last rectangle (the rest were "repainted over".
You want to loop through all of your tiles and use the drawRect method to draw them inside of your paintComponent method so they will be drawn every time.
public void paintComponent(Graphics g) {
super.paintComponent(g)
for(int k = 0; k <= 4; k++){
for(int j = 0; j <= 3; j++){
if(field[j][k]==null)continue;
stein=field[j][k];
g.setColor(stein.farbe);
g.fillRect((field[j][k].sX * PANELSIZE) , (field[j][k].sY * PANELSIZE) , ((((field[j][k].eX-field[j][k].sX) + 1) * PANELSIZE) -1), ((((field[j][k].eY-field[j][k].sY)+ 1) * PANELSIZE) -1));
}
}
}
I have been looking at this one for a while and it doesn't make sense. When I start my program, I set the background color of a grid of rectangles to a specific color using the SetupLawn call from my main function in a different file. That part works fine. Then when I try to change the color later by calling the SetupLawn function again with a new color it doesn't change. I put prints in the SetupLawn function and the color I am passing is getting there correctly but as soon as paintComponent gets called the value of currentColor is back to being what it was originally. I verified this with a debug print as well.
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class Lawn
{
public static class SetupLawn extends JPanel
{
private List<Point> lawn;
Color currentColor;
public SetupLawn(Color color)
{
lawn = new ArrayList<>(25);
currentColor = color;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for (Point cell : lawn)
{
int cellX = cell.x;
int cellY = cell.y;
g.setColor(currentColor);
g.fillRect(cellX, cellY, 50, 50);
}
//Set grid color and draw border
g.setColor(Color.BLACK);
g.drawRect(10, 10, 800, 500);
for (int i = 10; i <= 800; i += 50)
{
g.drawLine(i, 10, i, 510);
}
for (int i = 10; i <= 500; i += 50)
{
g.drawLine(10, i, 810, i);
}
for (int i = 60; i <= 750; i += 50)
{
for (int j =60; j <= 450; j += 50)
{
lawn.add(new Point(i, j));
}
}
}
}
}
Here is the way I was calling it.
Lawn.SetupLawn lawn = new Lawn.SetupLawn(spring);
I can see now why this method was not a good idea. It was really late at night when I was working on this and Java is not a strong language for me.
I wrote a checkerboard program (shown below). My problem is that I can't figure out how to center it with resize, and have it resize proportionately.
I added in a short statement. Int resize (shown below) I did something similiar with a previous program regarding a bullseye where I used a radius. I just haven't the slightest clue how to implement that in here.
import java.awt.*;
import javax.swing.JComponent;
public class CheckerboardComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
int s = 12;
int x = s;
int y = s;
// int resize = Math.min(this.getHeight(), this.getWidth()) / 8 ;
for (int i = 0; i < 8; i++) {
// one row
for (int j = 0; j < 8; j++) {
g2.fill(new Rectangle(x, y, 4 * s, 4 * s) );
x += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
x = s;
y += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
}
}
here is a viewer program
import javax.swing.*;
public class CheckersViewer {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(430, 450);
frame.setTitle("Checkerboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckerboardComponent component = new CheckerboardComponent();
frame.add(component);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Hmm... Here's one idea then, though it probably isn't a good one (I'm also not that good with jComponent and jFrame, so there's probably a better way and a more suited person)
I believe the component object has a built-in method called getSize(). If you can relate the size of the rectangle to the size of the window, then it could be resizable. Obviously there would be more code and arguments, but for example:
public void drawStuff(Component c)
{
...
Dimension size = c.getSize();
double RectWidth = (size.width)*(.05);
...
}
check this out for more complete examples:
http://www.javadocexamples.com/java/awt/Component/getSize().html
And I apologize I can't be of more help.