Painting array of constant size? - java

I am having trouble doing something fairly simple, painting an array of elements. Here is what I have for the paint method in the class with the array: (xB and yB are just the x and y values which I want to increment to make the instances show up in different locations).
public void paint(Graphics pane) {
private Box[] boxes = new Box[NUM_BOX];
for(int i = 0; i<NUM_BOX; i++){
if (xB == 290){
xB = 0;
yB = yB + 20;
}
boxes[i].paint(pane, xB, yB);
xB = xB + 20;
}
And here is what I have in the Box class which is what is being painted:
public class Box {
private final int WIDTH = 20;
private final int HEIGHT = 20;
private boolean up = true;
public void paint(Graphics pane, int x, int y) {
pane.setColor(Color.black);
pane.drawRect(x, y, WIDTH, HEIGHT);
pane.setColor(Color.gray);
pane.fill3DRect(x +2, y+2, WIDTH - 3, HEIGHT - 3, up);
}
}
Every time I run it, it tells me there is a NullPointerException at the boxes[i].paint(pane,xB,yB) line. What am I doing wrong?

Related

Is there a way to make a constructor that draws a rectangle

My partner and I are trying to remake Tetris for our final project of the year in my Computer Science class we currently have a for loop that draws individual rectangles in an overwritten paint method.
private final int spacer = 30;
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
for(int i = getHeight()/2 - (spacer * 10); i < getHeight()/2 + (spacer * 10); i += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += (spacer)) {
g.drawRect(x, i, (spacer), (spacer));
}
}
setForeground(Color.black);
}
The method basically takes the width and height of the window and makes a 10 x 20 grid of boxes that are 30 units, pixels I think, wide.
We'd like to make a Grid.java class that takes in color, the spacer int, and an x and y int. The constructor for Grid.java should draw the exact same thing as the code above using the for loop, but when we tried it gave us a white screen that would not resize with the window.
private final int spacer = 30;
private static Grid[][] arr = new Grid[10][20];
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
int countY = 0;
int countX = 0;
for(int y = getHeight()/2 - (spacer * 10); y < getHeight()/2 + (spacer * 10); y += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += spacer) {
arr[countX][countY] = new Grid(x, y, spacer, g);
countX++;
}
countY++;
}
setForeground(Color.black);
}
*Grid.java Class*
package Tetris_Shapes;
import javax.swing.*;
import java.awt.*;
public class Grid {
private int x;
private int y;
private int side;
private Graphics g;
public Grid(int x, int y, int side, Graphics g) {
// g.drawRect(x, y, spacer, spacer);
this.x = x;
this.y = y;
this.side = side;
this.g = g;
paint(this.g);
}
private void paint(Graphics g) {
g.drawRect(x, y, side, side);
}
}
When we try and run this we get the white box that doesn't resize. My question is does anyone know of a way to get a constructor to draw shapes. Thank you in advance, this is pretty niche so I'm also going to apologize in advance.

How to translate a rectangle to the previous mouse coordinates in processing

I'm brand new to java and I'm making a snake game. My next step is to add a rectangle to the snake whenever it eats food. My current thinking is, I want to add an identical rectangle that's translated to the previous position of (mouseX, mouseY). At least, translated a distance of one rectangle from the previous one, but oriented where the mouse previously was, to "follow" behind the piece in front of it. I'm not sure how to go about doing that, but here is my code thus far.
//snake
void snake() {
rect(mouseX, mouseY, 10, 10);
}
class Snake {
//variables
int len;
int wid;
int xcord;
int ycord;
//constructor
Snake(int x,int y, int len, int wid) {
this.len = len;
this.wid = wid;
this.xcord = x;
this.ycord = y;
rect(xcord, ycord, wid, len);
}
//clear screen
void update() {
background(255);
rectMode(CENTER);
rect(mouseX, mouseY, wid, len);
}
}
class Food {
//variables
int xcord;
int ycord;
int wid;
int len;
//constructor
Food() {
this.xcord = int(random(width - 5));
this.ycord = int(random(height - 5));
this.wid = 10;
this.len = 10;
rect(xcord, ycord, wid, len);
}
//update food position
void update() {
if( (mouseX > xcord) && (mouseX < xcord + wid) &&
(mouseY > ycord) && (mouseY < ycord + len)) {
xcord = int(random(width - 5));
ycord = int(random(height - 5));
//lengthen snake
}
}
//display food
void displayFood() {
rect(xcord, ycord, 10, 10);
}
}
Snake s;
Food f;
void setup() {
background(255);
s = new Snake(mouseX, mouseY, 10, 10);
f = new Food();
}
void draw() {
s.update();
f.update();
f.displayFood();
}
You make 2 variables
float pMouseX = mouseX;
float pMouseY = mouseY;
Then, in draw, after updating the snake, you update those variables:
s.update
pMouseX = mouseX;
pMouseX = mouseY;
For having more than 2 rectangles, instead of single variables, consider using an ArrayList of arrays.
An Array is basically a way to store multiple variables in one variable.
An ArrayList is similar, but it doesn't have a set size. This means that you can keep adding elements to ArrayLists, which is something you can't do with Arrays.
You can declare such an ArrayList like this:
ArrayList<float[]> arrayList = new ArrayList<float[]>(); //each element of the ArrayList is an array, which contains an x and y position
To get the x and y coordinates of any rectangle, use arrayList.get(indexOfTheRectangle)[0] //use 1 instead of 0 for the y coordinate
and update them like this:
for (int i = arrayList.length - i; i > 0; i++) { //you need to go through the array backwards, because otherwise, for each element, you end up changing the value it is supposed to get, which results in all elements having the same value.
arrayList[i] = arrayList[i - 1];
}
arrayList[0] = new float[]{mouseX, mouseY}

Create multiple of 1 objects next to each other (grid like)

Hey if i have a simple rectangle class, how can i make it so that it creates that rectangle next to each other in a grid like pattern? maybe like 10 rows 10 columns?
public class Vak {
private int posX = 0;
private int posY = 0;
private int width = 50;
private int height = 50;
private Color colour;
public Vak(Color c, int x, int y){
this.colour = c;
this.posX = x;
this.posY = y;
}
public int vakPosY(){
return this.posY;
}
public int vakPosX(){
return this.posX;
}
public void draw (Graphics g){
g.setColor(this.colour);
g.drawRect(posX, posY, width, height);
}
public void move(int numberPixelsX, int numberPixelsY){
this.posX = this.posX + numberPixelsX;
this.posY = this.posY + numberPixelsY;
}
}
this is my code for rectangle "vak"
Is this what you are looking for?
int mapWidth = 10;
int mapHeight = 10;
// tileWidth and tileHeight should probably be public static const fields or static readonly properties of some class, but I put them here for now.
int tileWidth = 50; // Pixels
int tileHeight = 50; // Pixels
// tiles should probably be a field of a Map class (if you have one)
Vak[][] tiles = new Vak[mapWidth][mapHeight];
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++)
{
tiles[x][y] = new Vak(Color.white, x*tileWidth, y*tileHeight);
}
}
And then in the drawing part of the main loop:
for(Vak[] row : tiles)
{
for(Vak tile : row)
{
tile.draw(g);
}
}

There is some space at the end of the bar chart I've created using Graphics

I am trying to make a bar chart. Everything goes fine; the code compiles and runs successfully. But the frame (window) is not packed perfectly. There is some space at the end of the bar chart. I just want this space removed.
public class BarChart extends JPanel{
int[] percentage;
Color color;
double barOffset;
public BarChart(int[] percentage, Color color) {
this.color = color;
this.percentage = percentage;
}
public BarChart(int[] percentage) {
this.color = Color.black;
this.percentage = percentage;
}
public BarChart() {
this.color = Color.black;
}
int w = 1,h = 1;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
w = getWidth();
h = getHeight();
g.setColor(color);
barOffset = w*0.05;
int barWidth = (int)(w*0.1);
for(int i = 0; i<percentage.length; i++) {
g.fillRect((int)(barOffset),(int)(h*0.95-2*percentage[i]), barWidth, 2*percentage[i]);
if(i < percentage.length-1)
barOffset = (i+2)*w*0.05 + (i+1)*(barWidth);
}
}
}
This was not a packing error, but rather you were drawing off the edge of the component. To check for packing errors, set a background color for the container that is distinct from the component color.
For the set int[] p = new int[]{100, 5, 6, 9, 1, 0, 5, 100};, your bars are being drawn as follows:
component dimensions: width=104 height=10
bar[0]: xLeft=5 yTop=-190 barWidth=10 barHeight=200
bar[1]: xLeft=20 yTop=0 barWidth=10 barHeight=10
bar[2]: xLeft=35 yTop=-2 barWidth=10 barHeight=12
bar[3]: xLeft=50 yTop=-8 barWidth=10 barHeight=18
bar[4]: xLeft=66 yTop=7 barWidth=10 barHeight=2
bar[5]: xLeft=81 yTop=9 barWidth=10 barHeight=0
bar[6]: xLeft=96 yTop=0 barWidth=10 barHeight=10
bar[7]: xLeft=111 yTop=-190 barWidth=10 barHeight=200
I think this produces what you're looking for. Drawing components can be tricky, and the way I mitigate the complexity is to keep track of my screen locations semantically.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BarChart extends JPanel
{
public static void main(String[] args)
{
int[] p = new int[]{100, 5, 6, 9, 1, 0, 5, 100};
JFrame f = new JFrame();
f.setBackground(Color.BLUE);
BarChart chart = new BarChart(p);
chart.setBackground(Color.RED);
f.add(chart);
f.pack();
f.show();
}
private int[] percentage;
private Color color;
private boolean padEnds = true;
public BarChart(int[] percentage, Color color)
{
this.percentage = percentage;
this.color = color;
return;
}
public BarChart(int[] percentage)
{
this(percentage, Color.BLACK);
return;
}
public BarChart()
{
this(new int[0]);
return;
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(this.color);
int width = super.getWidth();
int height = super.getHeight();
int topPadding = Math.round(height * 0.05f);
int barCount = this.percentage.length;
int barOffset = Math.round(width * 0.025f); // 2.5% (in pixels) reserved space on both sides of each bar == 5% between bars
int totalOffsetWidth = (barOffset * 2) * barCount;
if (!this.padEnds)
{
totalOffsetWidth -= (barOffset * 2);
}
int availableWidth = width - totalOffsetWidth;
int availableHeight = height - topPadding;
int barWidth = (int) Math.floor((float) availableWidth / (float) barCount);
int xLeft = 0;
for (int i = 0; i < barCount; i++)
{
int percent = this.percentage[i];
if (this.padEnds || (i != 0))
{
xLeft += barOffset; // Add offset here to pad left side of each bar.
}
int barHeight = Math.round(((float) availableHeight) * ((float) percent / 100f));
int yTop = topPadding + (availableHeight - barHeight);
g.fillRect(xLeft, yTop, barWidth, barHeight);
xLeft += barWidth; // advance the next drawing position
if (this.padEnds || (i != (barCount - 1)))
{
xLeft += barOffset; // Add offset here to pad right side of each bar.
}
}
return;
}
}

Trying to draw lines with JPanel

I am trying to draw lines using JPanel and I have hit somewhat of a wall. I can get two sides down but once it comes to subtracting from the x cord it all goes wrong.
package GUIstuff;
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawPanel extends JPanel{
public void paintComponent (Graphics g){
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int drawCounter = 0; // counters for all the while statements
int drawCounter2 = 0;
int drawCounter3 = 0;
int drawCounter4 = 0;
int x1 = 0; // cords change with the while statemetns
int x2 = 0;
int y1 = 0;
int y2 = 0;
while (drawCounter <= 15){ // counter
y2 = 250;
g.drawLine(x1, y1, x2, y2);
x2 = x2 + 15;
y1 = y1 + 15;
drawCounter++; }
int u1 = 0;
int u2 = 0;
int v1 = 0;
int v2 = 0;
while (drawCounter2 <= 15){
u2 = 250;
g.drawLine(u1, v1, u2, v2);
u1 = u1 + 15;
v2 = v2 + 15;
drawCounter2++;
}
int a1 = 0;
int a2 = 0;
int b1 = 0;
int b2 = 0;
while (drawCounter3 <= 15){
a2 = 250;
g.drawLine(a1, b1, a2, b2);
b1 = b1 + 15;
a2 = a2 - 15;
drawCounter3++;
}
}
}
Here is my runner class
package GUIstuff;
import javax.swing.JFrame;
public class DrawPanelTest {
public static void main (String args[]){
DrawPanel panel = new DrawPanel();
JFrame application = new JFrame();
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(panel);
application.setSize (250, 250);
application.setVisible(true);
}
}
I have a the lines in the bottom left and the upper right but when I try to subtract from x I just get lines going a crossed the whole box.
When doing custom painting you should override the getPreferredSize() method so the panel can be displayed at its preferred size.
When you draw the lines two variable are the same and two variables differ. Use the width/height variable when appropriate instead of hardcoding a number. In the example below I did the left and bottom sides. The bottom side shows how to subtract. I'll let you figure out the pattern for the other two side.
Also, I made the panel a little more dynamic so it will be easy to configure the number of lines you want painted and the gap between the lines.
import java.awt.*;
import javax.swing.*;
public class DrawSSCCE extends JPanel
{
private int lines;
private int lineGap;
public DrawSSCCE(int lines, int lineGap)
{
this.lines = lines;
this.lineGap = lineGap;
}
#Override
public Dimension getPreferredSize()
{
int size = lines * lineGap;
return new Dimension(size, size);
}
#Override
public void paintComponent(Graphics g)
{
int width = getWidth();
int height = getHeight();
// Draw lines starting from left to bottom
int x = lineGap;
int y = 0;
for (int i = 0; i < lines; i++)
{
g.drawLine(0, y, x, height);
x += lineGap;
y += lineGap;
}
// Draw lines starting from bottom to right
x = 0;
y = height - lineGap;
for (int i = 0; i < lines; i++)
{
g.drawLine(x, height, width, y);
x += lineGap;
y -= lineGap;
}
// Draw lines starting from right to top
// Draw lines starting from top to left
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("DrawSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new DrawSSCCE(15, 15) );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
One way to draw this type of graphic would be to divide the drawing into quadrants. Here's a GUI I came up with.
This drawing is created by drawing lines all around the rectangle.
I created a JFrame and a drawing JPanel. I created the drawing JPanel by dividing the horizontal width and vertical height into the same number of increments. Since the width is greater than the height, the width increment is greater than the height increment.
I divided the drawing into quarters, and worked on the code for each quarter separately, using fewer and larger increments. Once I had all four quarters working, I quadrupled the number of increments and divided the width increment and the height increment by four.
Here's the complete runnable code.
import java.awt.BorderLayout;
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 DrawOvalRectangle implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawOvalRectangle());
}
#Override
public void run() {
JFrame frame = new JFrame("Curved Lines 2021");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private int width, height, margin, increments, xIncrement, yIncrement;
public DrawingPanel() {
this.margin = 10;
this.increments = 80;
this.xIncrement = 8;
this.yIncrement = 6;
this.width = increments * xIncrement;
this.height = increments * yIncrement;
this.setPreferredSize(new Dimension(
width + margin + margin, height + margin + margin));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
drawNorthwestQuadrant(g);
drawNortheastQuadrant(g);
drawSouthwestQuadrant(g);
drawSoutheastQuadrant(g);
}
private void drawNorthwestQuadrant(Graphics g) {
int x1 = margin;
int y1 = height + margin;
int x2 = margin;
int y2 = margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x2 += xIncrement;
y1 -= yIncrement;
}
}
private void drawNortheastQuadrant(Graphics g) {
int x1 = margin;
int y1 = margin;
int x2 = width + margin;
int y2 = margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x1 += xIncrement;
y2 += yIncrement;
}
}
private void drawSouthwestQuadrant(Graphics g) {
int x1 = margin;
int y1 = height + margin;
int x2 = margin;
int y2 = margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x1 += xIncrement;
y2 += yIncrement;
}
}
private void drawSoutheastQuadrant(Graphics g) {
int x1 = margin;
int y1 = height + margin;
int x2 = width + margin;
int y2 = height + margin;
for (int index = 0; index < increments; index++) {
g.drawLine(x1, y1, x2, y2);
x1 += xIncrement;
y2 -= yIncrement;
}
}
}
}

Categories

Resources