(Java) Drawn Rectangles do not appear - java

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));
}
}
}

Related

Jpanel 2d array of objects drawing problem

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.

How to add multiple rectangles to a jframe(trying to code 2048 in an easy way)

I made the game already and wanted to make my GUI look better with rectangles not with jlabels and now I´ve come to realize that only the last rectangle that is drawn is shown on the GUI
I already tried it with different layouts
my GUI class:
public class GUI_N
{
private Spiel spiel;
private KeyEvent e;
private String beste;
private int beste1;
private DrawingComponent[][] feld;
GUI_N(){
feld = new DrawingComponent[4][4];
spiel = new Spiel();
beste1 = 0;
beste = "Highscore: "+beste1;
JFrame g=new JFrame("2048 - Main");
g.setSize(500,500);
g.setFocusable(true); //wichtig für KeyListener
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int i = 0;
int j = 0;
int h = 0;
int l = 0;
while(i<4)
{
while(j<4)
{
if(i==0){
h = 50;
}else if(i==1){
h = 100;
}else if(i==2){
h = 150;
}else if(i==3){
h = 200;
}
if(j==0){
l = 50;
}else if(j==1){
l = 100;
}else if(j==2){
l = 150;
}else if(j==3){
l = 200;
}
feld[i][j] = new DrawingComponent(l,h,50,50);
feld[i][j].setBounds(l,h,50,50);
j++;
}
j=0;
i++;
}
i = 0;
j = 0;
while(i<4)
{
while(j<4)
{
g.add(feld[i][j]);
j++;
}
j=0;
i++;
}
//g.getContentPane().setBackground(new Color(20, 40, 50));
g.setVisible(true);
}
public static void main(String[] args) {
new GUI_N();
}
}
my rectangle class:
public class DrawingComponent extends JComponent
{
private Graphics2D g2;
private int wert;
private int x;
private int y;
private int w;
private int h;
public DrawingComponent(int px,int py,int pw,int ph)
{
x=px;
y=py;
w=pw;
h=ph;
}
public void paintComponent(Graphics g)
{
g2 = (Graphics2D) g;
Rectangle rect1 = new Rectangle(x,y,w,h);
g2.setColor(Color.RED);
g2.fill(rect1);
}
public void setWert(int x)
{
wert = x;
}
public int getWert()
{
return wert;
}
}
as I said only the last drawn rectangle is shown.
How do I achieve this?
Right now you're adding the rectangles directly to your frame. You should have a JPanel layer in between, to which you can give a LayoutManager (GridLayout would be a good one to look at) to arrange all your rectangles.
So you would have something like this:
JFrame g = new JFrame("2048 - Main");
// GridLayout (on next line) takes number of rows and columns
JPanel panel = new JPanel(new GridLayout(4, 4));
// ... add all the rectangles to the panel here
g.add(panel);
And then you would add your rectangles to the panel, not the frame. As you add them, they will automatically go into place in the grid.
panel.add(feld[i][j]);
Also, if you use GridLayout, it will resize and fit the components to the grid dynamically, so it may save you some code as well, since you wouldn't need to hardcode their sizes in the GUI class.

JFrame defined in one class, JComponent extended in another

Relatively new to Java, coding for a school project.
I'm using JFrame and JComponent, drawing patterns and strings and all that fun stuff.
Currently, I have a class written that extends JComponent. This is the class where I am defining most of my shapes. The issue is that I initialized my Jframe
(Code: JFrame myFrame = new JFrame() ) in the main of one class, but I need to access myFrame.getWidth() in the JComponent class that I'm working in.
How can I access variables getWidth() and getHeight() in "public class MyJComponent extends JComponent" , when I defined myFrame in 'public class Lab2' ??
Edit for code:
public class Lab2 {
public static void main(String[] args) {
System.out.println("Hello Java");
JFrame myFrame = new JFrame();
myFrame.setSize(500, 500);
myFrame.setTitle("Color Test");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyJComponent myComponent = new MyJComponent(500, 500);
myFrame.add(myComponent);
myFrame.getContentPane().setBackground(Color.white); //sets background color.
myFrame.setVisible(true); // setVisible() *after* add() is the norm
//Deciding geometry of hidden shape. paintComponent is called once per run, this is called afterwards.
}
}
/**/
public class MyJComponent extends JComponent {
int[] circleX;
int[] circleY;
int[] circleR;
final int MIN_RADIUS = 5;
final int MAX_RADIUS = 15;
final int MIN_SEPARATION = 1;
final int MAX_ATTEMPTS = 5000;
final int MAX_CIRCLES = 1000;
Random rand;
int initialWidth;
int initialHeight;
int numCircles; // actual number of circles drawn
// are circles at index i and index j separated by *<= tolerance* pixels?
boolean twoCirclesOverlap(int i, int j, int tolerance) {
double distanceBetweenCenters =
Math.sqrt((circleX[i] - circleX[j]) * (circleX[i] - circleX[j]) +
(circleY[i] - circleY[j]) * (circleY[i] - circleY[j]));
return (distanceBetweenCenters <= (circleR[i] + circleR[j] + tolerance));
}
// are any existing circles separated from the proposed one at index i by *<= tolerance* pixels?
boolean anyCirclesOverlap(int i, int tolerance) {
for (int j = 0; j < i; j++) {
if (twoCirclesOverlap(i, j, tolerance)) {
return true;
}
}
return false;
}
// attempt to randomly place the largest-possible circle that does not overlap any existing one
boolean tryToPlaceCircle(int i) {
for (int j = 0; j < MAX_ATTEMPTS; j++) {
// pick a random position, set initial radius to minimum
circleX[i] = rand.nextInt(initialWidth);
circleY[i] = rand.nextInt(initialHeight);
circleR[i] = MIN_RADIUS;
// grow circle until it touches another or reaches max size
while (!anyCirclesOverlap(i, MIN_SEPARATION) && circleR[i] < MAX_RADIUS)
circleR[i]++;
// it was touching from the start -- must try again
if (circleR[i] == MIN_RADIUS) {
continue;
}
// grew to max size -- well done
else if (circleR[i] == MAX_RADIUS) {
return true;
}
// grew some, but then touched
else {
circleR[i]--; // retract to the step before touch
return true;
}
}
// all attempts failed
return false;
}
MyJComponent(int width, int height) {
circleX = new int[MAX_CIRCLES];
circleY = new int[MAX_CIRCLES];
circleR = new int[MAX_CIRCLES];
initialWidth = width;
initialHeight = height;
rand = new Random();
numCircles = 0;
while (numCircles < MAX_CIRCLES && tryToPlaceCircle(numCircles)) {
numCircles++;
}
}
//Override paintComponent
public void paintComponent(Graphics g) {
for (int i = 0; i < numCircles; i++) {
g.drawOval(circleX[i] - circleR[i], circleY[i] - circleR[i], 2 * circleR[i], 2 * circleR[i]);
}
}
//Shape decision
public void shapeDecision() {
double randomShapeDecider = Math.random();
if (randomShapeDecider > .50) {
//shape is circle, define it's properties
hiddenCircleDiameter = myFrame.getWidth();
}
else {
//shape is rectangle
hiddenRectangleWidth = myFrame.getWidth();
}
}
}

Drawing a two colored checker board with nested for loops where each square being their own object (Java)

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);
}
}

Draw random circles, coloring in red any circle not intersecting another circle

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]);
}
}

Categories

Resources