As part of my assignment, I'm supposed to make a shape that moves when the keyboard is pressed, and also changes color as it moves. I'm trying to add duplicate shapes that move when selected by clicking on them. However, for some reason, I can't add more than one shape. Here's my code. WARNING: MySimplePanel is very long, but the comments explain what my code does.
import java.awt.Graphics2D;
public interface ActionShape {
/**
* Calls the draw method inherited from the shape
* #param g
*/
public void draw(Graphics2D g);
public boolean contains(double x, double y);
public double getWidth();
public double getHeight();
public void setFrame(double x, double y, double w, double h);
}
Driver.java
public class Driver {
public static void main(String args[]) {
MySimplePanel panel = new MySimplePanel(800, 800, Color.gray);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static float random(float lower, float upper) {
float rand = (float) Math.random();
float range = upper - lower;
rand = range * rand;
System.out.println((lower + rand));
return (lower + rand);
}
}
myShape.java
public class myShape extends Rectangle2D.Double implements ActionShape{
static final int size = 50;
Ellipse2D oval;
Ellipse2D oval2;
Ellipse2D oval3;
public int red=127;
public int green=127;
public int blue = 0;
public myShape(int x, int y) {
//sets position of square to center
super(x-size/2, y-size/2, size, size);
oval = new Ellipse2D.Double(x-size/2, y - size, size, size);
oval2 = new Ellipse2D.Double(x-size/2, y + size/25, size, size);
oval3 = new Ellipse2D.Double(x - size, y-size/2, size, size);
}
/**
* Move all the shapes comprising this one
* #return
*/
#Override
public void draw(Graphics2D g) {
// TODO Auto-generated method stub
g.setColor(Color.black);
g.draw(this); //draw outline
g.draw(oval);
g.draw(oval2);
g.draw(oval3);
g.setColor(new Color(red,green,blue));//set color of all shapes
g.fill(this); //draw inside
g.fill(oval);
g.fill(oval2);
g.fill(oval3);
}
public void setFrame(double x, double y, double w, double h) {
super.setFrame(x, y, w, h);
oval.setFrame(x, y-size/2, w, h);
oval2.setFrame(x, y+size/2, w, h);
oval3.setFrame(x-size/2, y, w, h);
}
public boolean contains(double x, double y) {
if(super.contains(x, y) || oval.contains(x, y)|| oval2.contains(x, y)|| oval3.contains(x, y)) {
return true;
}else {
return false;
}
}
}
MySimplepanel
public class MySimplePanel extends JPanel implements MouseInputListener, KeyListener{
public static final int MOVE_PER_ARROW_KEY = 5; //variable that determines how many spaces the shape will move.
private int width;
private int height;
private boolean isPressed = false;
private boolean rightPressed = false;
private boolean otherPressed = false;
public myShape shape;
public int maxRed = 255;
public int maxGreen = 255;
public int maxBlue = 255;
public myShape selShape=null;
public int nextShape=0;
//An array of different shapes that all share an interface. This will be used when the right mouse button is pressed
public myShape[] shapes;
/**
* Construct a panel with specified width, height, and background color
* #param width
* #param height
* #param bgColor
*/
public MySimplePanel(int width, int height, Color bgColor) {
this.setPreferredSize(new Dimension(width, height));
this.setBackground(bgColor);
//Start to listen to mouse and keyboard input on this panel
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.addKeyListener(this); //detect keyboard input
this.setFocusable(true); //allows you to select this window (required to be able to type in it, just like Processing)
this.setFocusTraversalKeysEnabled(false); //disables shift and tab
setup();
}
private void setup() {
//sets up the starting coordinates for each shape the shape is going to be on the panel.
//I still need to align the center of the panel with the shape's center.
shape = new myShape(400,400);
shapes = new myShape[100];
//array of shapes
shapes[nextShape] = new myShape(200,200);
repaint();
}
/**
* This method is called whenever you call repaint();
*/
protected void paintComponent(Graphics graphicHelper) {
super.paintComponent(graphicHelper); //basically background() in Processing, erases everything
Graphics2D g = (Graphics2D) graphicHelper; //used for drawing in 2D mode
//width and height of the panel
width= getWidth();
height = getHeight();
//draws the shape.
shape.draw(g);
for(int i=0;i<nextShape;i++) {
shapes[i].draw(g);
g.setColor(Color.red);
g.draw(shapes[i]);
}
//for the very first shape that is drawn
if(isPressed==true) {
shape.draw(g);
g.setColor(Color.red);
g.draw(shape);
System.out.println("Shape pressed");
}
//for the very other shape that is drawn by right-clicking
if(otherPressed==true) {
for(int i=0;i<nextShape;i++) {
selShape.draw(g);
g.setColor(Color.red);
g.draw(selShape);
System.out.println("Other Shape pressed");
}
}
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
if(arg0.getButton() == MouseEvent.BUTTON1) {
if(shape.contains(arg0.getX(), arg0.getY())) {
selShape=shape;
isPressed=true;
repaint();
}
}
if(arg0.getButton() == MouseEvent.BUTTON1) {
for(int i=0; i<nextShape; i++) {
if(shapes[i]!=null) {
if(shapes[i].contains(arg0.getX(), arg0.getY())) {
selShape=shapes[i];
otherPressed=true;
repaint();
}
}
}
}
if(arg0.getButton() == MouseEvent.BUTTON3) {
rightPressed=true;
if(rightPressed==true) {
selShape=shapes[nextShape];
nextShape++;
repaint();
}
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent arg0) {
}
#Override
public void keyPressed(KeyEvent arg0) {
/**
* Scales the values of red and green based on the width and height respectively.
* red = 0 when the shape is all the way on the left, red = 255 when the shape is all the way on the right
* green = 0 when the shape is all the way up, green = 255 when the shape is all the way down
*/
selShape.red=(int) ((maxRed)*selShape.x/width);
selShape.green=(int) ((maxGreen)*selShape.y/height);
/**
* These two if statements are meant to keep the shape from moving off screen.
*/
if(selShape.x>width||selShape.x<(width=0)) {
selShape.x=width;
}
if(selShape.y>height||selShape.y<(height=0)) {
selShape.y=height;
}
/**
* Moves the shape in different directions depending on the key pressed. It also changes the values of red and green
*/
if(arg0.getKeyCode() == KeyEvent.VK_DOWN) {
selShape.setFrame(selShape.x, selShape.y + MOVE_PER_ARROW_KEY,
selShape.width, selShape.height);
selShape.green--;
repaint();
}else if(arg0.getKeyCode() == KeyEvent.VK_UP) {
selShape.setFrame(selShape.x, selShape.y - MOVE_PER_ARROW_KEY,
selShape.width, selShape.height);
selShape.green++;
repaint();
}else if(arg0.getKeyCode() == KeyEvent.VK_LEFT) {
selShape.setFrame(selShape.x - MOVE_PER_ARROW_KEY, selShape.y,
selShape.width, selShape.height);
selShape.red--;
repaint();
}else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
selShape.setFrame(selShape.x + MOVE_PER_ARROW_KEY, selShape.y,
selShape.width, selShape.height);
selShape.red++;
repaint();
}
/**
* If the shape reaches a certain spot, it will keep changing color randomly until it leaves that area.
*
* Still trying to get the shape's center to hit that spot.
*
*/
if(selShape.getCenterX()>=50 && selShape.getCenterX()<=150 && selShape.getCenterY()>=50 && selShape.getCenterY()<=150) {
selShape.red=(int)(Math.random()*maxRed)+1;
selShape.green=(int)(Math.random()*maxGreen)+1;
selShape.blue=(int)(Math.random()*maxBlue)+1;
System.out.println("x: "+selShape.x);
System.out.println("y: "+selShape.y);
}
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
myShape.java
public class myShape extends Rectangle2D.Double implements ActionShape {
static final int size = 50;
Ellipse2D oval;
Ellipse2D oval2;
Ellipse2D oval3;
public int red = 127;
public int green = 127;
public int blue = 0;
public myShape(int x, int y) {
// sets position of square to center
super(x - size / 2, y - size / 2, size, size);
oval = new Ellipse2D.Double(x - size / 2, y - size, size, size);
oval2 = new Ellipse2D.Double(x - size / 2, y + size / 25, size, size);
oval3 = new Ellipse2D.Double(x - size, y - size / 2, size, size);
}
/**
* Move all the shapes comprising this one
*
* #return
*/
#Override
public void draw(Graphics2D g) {
// TODO Auto-generated method stub
g.setColor(Color.black);
g.draw(this); // draw outline
g.draw(oval);
g.draw(oval2);
g.draw(oval3);
g.setColor(new Color(red, green, blue));// set color of all shapes
g.fill(this); // draw inside
g.fill(oval);
g.fill(oval2);
g.fill(oval3);
}
public void setFrame(double x, double y, double w, double h) {
super.setFrame(x, y, w, h);
oval.setFrame(x, y - size / 2, w, h);
oval2.setFrame(x, y + size / 2, w, h);
oval3.setFrame(x - size / 2, y, w, h);
}
public boolean contains(double x, double y) {
if (super.contains(x, y) || oval.contains(x, y) || oval2.contains(x, y) || oval3.contains(x, y)) {
return true;
} else {
return false;
}
}
Related
I created a program that makes multiple bouncing balls with random color, speed and radius. When user clicks on the screen a new random ball should appear and move around screen. But i have a multi-thread issue. When i click on the screen a ball appears and doesn't moving at all. When another click comes nothing happens.
BouncingBalls Class
public class BouncingBalls extends JPanel implements MouseListener{
private Ball ball;
protected List<Ball> balls = new ArrayList<Ball>(20);
private Container container;
private DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public static final int UPDATE_RATE = 30;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height){
canvasWidth = width;
canvasHeight = height;
ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
}
public void start(){
Thread t = new Thread(){
public void run(){
while(true){
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {}
}
}
};
t.start();
}
public void update(){
ball.move(container);
}
class DrawCanvas extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
container.draw(g);
ball.draw(g);
}
public Dimension getPreferredSize(){
return(new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame f = new JFrame("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(500, 500));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
count++;
balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
balls.get(count-1).start();
start();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Ball Class
import java.awt.Color;
import java.awt.Graphics;
public class Ball{
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private BouncingBalls balls;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int i = 0;
public Ball(int x, int y, int speedX, int speedY, int radius, int red, int green, int blue){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.radius = radius;
this.red = red;
this.green = green;
this.blue = blue;
}
public void draw(Graphics g){
for(Ball ball : balls){
g.setColor(new Color(red, green, blue));
g.fillOval((int)(x - radius), (int)(y - radius), (int)(2 * radius), (int)(2 * radius));
}
}
public void move(Container container){
x += speedX;
y += speedY;
if(x - radius < 0){
speedX = -speedX;
x = radius;
}
else if(x + radius > 500){
speedX = -speedX;
x = 500 - radius;
}
if(y - radius < 0){
speedY = -speedY;
y = radius;
}
else if(y + radius > 500){
speedY = -speedY;
y = 500 - radius;
}
}
}
Container Class
import java.awt.Color;
import java.awt.Graphics;
public class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g){
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
You're maintaing two different references to your ball.
You have a reference to a single Ball called ball and a List of balls. Your update and paint methods only reference the single ball
Ball doesn't seem to have a start method (that I can see) so this balls.get(count-1).start(); doesn't make sense...
Updated
You don't need the reference to ball
While not a bad idea, while testing, you should probably call start in the constructor
Your update method in BouncingBalls should looping through the balls list, calling move on each ball in the list...
The paintComponent method of DrawCanvas needs access to and should make use of the balls list. This might be better achievable through a model interface
Do not construct a new Ball with parameters, as it's giving each ball the same properties, especially when you assign random values to it when you construct it any way...
Ball doesn't have (or need) a start method
public class BouncingBalls extends JPanel implements MouseListener {
// private Ball ball;
protected List<Ball> balls = new ArrayList<Ball>(20);
private Container container;
private DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public static final int UPDATE_RATE = 30;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height) {
canvasWidth = width;
canvasHeight = height;
// ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
start();
}
public void start() {
Thread t = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {
}
}
}
};
t.start();
}
public void update() {
for (Ball ball : balls) {
ball.move(container);
}
}
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (Ball ball : balls) {
ball.draw(g);
}
// ball.draw(g);
}
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(500, 500));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
count++;
balls.add(new Ball());
// balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
// balls.get(count - 1).start();
// start();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public static class Ball {
public int random(int maxRange) {
return (int) Math.round(Math.random() * maxRange);
}
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int i = 0;
public Ball() { //int x, int y, int speedX, int speedY, int radius, int red, int green, int blue) {
// this.x = x;
// this.y = y;
// this.speedX = speedX;
// this.speedY = speedY;
// this.radius = radius;
// this.red = red;
// this.green = green;
// this.blue = blue;
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius), (int) (2 * radius));
}
public void move(Container container) {
x += speedX;
y += speedY;
if (x - radius < 0) {
speedX = -speedX;
x = radius;
} else if (x + radius > 500) {
speedX = -speedX;
x = 500 - radius;
}
if (y - radius < 0) {
speedY = -speedY;
y = radius;
} else if (y + radius > 500) {
speedY = -speedY;
y = 500 - radius;
}
}
}
public static class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g) {
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
}
Updated
As pointed out by the commentators, ArrayList is not thread safe, it's not a good idea to have multiple threads trying to access it simultaneously. While adding is slightly safer then removing, it is still bad practice.
You can either replace ArrayList with Vector, which would be the simpler solution, or synchronize the access to the list around a common monitor lock. Given your example, I'd use a java.util.Vector
You Can try this alternate Java Programm for bouncing 10 multi-colored balls on a single "START" button.....
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javaimage.io.*;
class Thr extends Thread
{
boolean up=false;
Ballbounce parent;
int top,left;
Color c;
Thr(int t,int l,Color cr,ex5 p)
{
top=l;
if(top > 170)
top=170-t/8;
left=t;
c=cr;
parent=p;
}
public void run()
{
try
{
while(true)
{
Thread.sleep(37);
if(top >= 188)
up=true;
if(top <= 0)
up=false;
if(!up)
top=top+2;
else
top=top-2;
parent.p.repaint();
}
}catch(Exception e){}
}
}
class Ballbounce extends JFrame implements ActionListener
{
int top=0,left=0,n=0,radius=50;
Color C[]={Color.black,Color.cyan,Color.orange,Color.red,Color.yellow,Color.pink,Color.gray,Color.blue,Color.green,Color.magenta};
Thr t[]=new Thr[10];
GPanel p;
JButton b;
Panel p1;
Ballbounce()
{
setSize(700,300);
setVisible(true);
setLayout( new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(p=new GPanel(this),BorderLayout.CENTER);
b= new JButton("Start");
b.addActionListener(this);
add(p1=new Panel(),BorderLayout.SOUTH);
p1.setBackground(Color.lightGray);
p1.add(b);
}
public static void main(String args[])
{
new Ballbounce();
}
public void actionPerformed(ActionEvent e)
{
t[n]=new Thr(left+(radius+13)*n+29,top+n*25,C[n],this);
t[n].start();
n++;
p.repaint();
if(n >9)
b.setEnabled(false);
}
}
class GPanel extends JPanel
{
Ballbounce parent;
GPanel(Ballbounce p)
{
parent=p;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.white);
for(int i=0;i< parent.n;i++)
{
g.setColor(parent.t[i].c);
g.fillOval(parent.t[i].left,parent.t[i].top,parent.radius,parent.radius);
}
}
}
I hope you will like it....
If u are unable to understand the code... You can question it anytime...... :)
Enjoy the code... :)
I'm writing a program that displays a circle every time you click the Jpanel. I have it all set up and I want to be able to use the drawCircle method I created in my circle class to draw the circles in the paintComponent method. I'm storing all of the circles created in a linked list. Then I interate through each Circle in the list and try to use the method in my Circle class called drawCircle().
For some reason, if I try to use c1.drawCircle() in a for loop in the My panel class it only draws the last circle that was created. But if I just use g.fillOval(with the correct parameters grabbing the values from the Circle class) in the for loop it works properly and displays all the circles. Why is it doing this and how do I go about using the method in the Circle class properly
I'm unsure what to try right now.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
public class MouseTest {
private int borderWidth = 20;
private JFrame frame;
private boolean tracking;
private boolean start;
private boolean clearBol;
private int xstart;
private int ystart;
private int xend;
private int yend;
private LinkedList<Circle> circles;
public MouseTest() {
tracking = false;
start = false;
circles = new LinkedList<Circle>();
frame = new JFrame();
frame.setBounds(250, 98, 600, 480);
frame.setTitle("Window number three");
Container cp = frame.getContentPane();
JButton clear = new JButton("Clear");
JToggleButton circleButton = new JToggleButton()("Circles");
JToggleButton drawButton = new JToggleButton("Draw");
ButtonGroup circleOrDraw = new ButtonGroup();
MyPanel pane = new MyPanel();
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
clearBol = true;
frame.repaint();
}
});
JPanel top = new JPanel();
top.setLayout(new FlowLayout());
top.add(clear);
circleOrDraw.add(circleButton);
circleOrDraw.add(drawButton);
top.add(circleOrDraw);
cp.add(top, BorderLayout.NORTH);
cp.add(pane, BorderLayout.CENTER);
pane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
xstart = e.getX();
ystart = e.getY();
start = false;
}
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
if (xend < xstart) {
int tmp = xstart;
xstart = xend;
xend = tmp;
}
if (yend < ystart) {
int tmp = ystart;
ystart = yend;
yend = tmp;
}
start = true;
frame.repaint();
}
});
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
if (tracking) {
int x = e.getX();
int y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
});
frame.setVisible(true);
} // constructor
public static void main(String[] arg) {
MouseTest first = new MouseTest();
} // main
public void msg(String s) {
System.out.println(s);
}
public void trackMouse() {
tracking = !tracking;
} // trackMouse
public class Circle extends JPanel {
Graphics g;
int x;
int y;
int r;
Color color;
public Circle(Graphics g, int x, int y, int r) {
this.g = g;
this.x = x;
this.y = y;
this.r = r;
int red = (int) (256 * Math.random());
int green = (int) (256 * Math.random());
int blue = (int) (256 * Math.random());
this.color = new Color(red, green, blue);
}
public void drawCircle() {
int x2 = x - (r / 2);
int y2 = y - (this.r / 2);
g.setColor(color);
g.fillOval(x2, y2, this.r, this.r);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public int getR() {
return r;
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
if (start) {
circles.add(new Circle(g, xend, yend,
(int) ((250 * Math.random() + 4))));
//Area where I'm having issues
for (Circle c1 : circles) {
msg("" + c1.getX());
// this method that I created in the circle class will only draw the first circle
//c1.drawCircle();
int r = c1.getR();
int x = c1.getX();
int y = c1.getY();
g.setColor(c1.getColor());
g.fillOval((c1.getX() - (r / 2)), (c1.getY() - (r / 2)),
r, r); // this will display all the circles
}
int size = circles.size();
msg(size + " Size");
msg("" + circles.getLast().getX());
}
if (clearBol) {
super.paintComponent(g);
circles.clear();
clearBol= false;
}
Thank you!
Most of the structure of your class needs to be changed
Your MyPanel should have a better name to give its functionality, maybe something like DrawingPanel.
The DrawingPanel is then responsible for managing the Circles to be painted. So typically you would just use an ArrayList to hold the Circle information.
Then you would add a method to the class, like addCircle(...) to add the Circle information to the ArrayList and then invoke repaint().
Then in your paintComponent(...) method the first thing you do is invoke super.paintComponent(...) to clear the panel. Then you iterate through the ArrayList and paint all the Circles. There will be no need for the Boolean values to check the state of the class. The ArrayList will either have circles or it won't.
You would also need a method like clearCircles(). This would simply remove all the Circles from the ArrayList and invoke repaint() on itself.
Your Circle class should NOT extend JPanel. It should just be a class that contains the information need to paint the circle: x/y location, size of circle and color of circle.
Now your frame is responsible of displaying your DrawingPanel and the buttons.
When you click the "Clear" button you simply invoke the clearCircles() method of the DrawingPanel.
For your MouseListener you simply invoke the addCircle(...) method of your DrawingPanel once you have all the information needed to create a Circle instance.
For a complete working example that incorporates all these suggestions check out the DrawOnComponent example found in Custom Painting Approaches
I am trying to write a program that will allow me to remove a shape if the right mouse click is inside the shape. My approach was to include a method to find the min and max X & Y coordinates of the shape and remove it if the mouse click if the X & Y coordinates of the click are between those coordinates. Right now, my code is just removing the last shape that I spawned in my array list of shapes.
public class RemoveCircle extends JPanel
{
private JFrame framey;
private JPanel panels1;
Circle c1 = new Circle(100,100);
private int x, y;
MouseClicks ms1;
ArrayList<Circle> circles = new ArrayList<Circle>();
private int clickcount;
public RemoveCircle()
{
framey = new JFrame("RemoveCircle");
framey.setSize(900,900);
ms1 = new MouseClicks();
//circles.add(new Circle(x,y));//This may be the original circle being added
this.setBackground(Color.BLACK);
this.setPreferredSize(new Dimension(900,900));
framey.add(this);
framey.pack();
framey.setVisible(true);
this.addMouseListener(ms1);
}
public class Circle
{
int x, y;
Color c1;
int minsx, maxsx, minsy, maxsy;
public Circle(int x, int y)
{
this.x = x; this.y = y;
c1 = getRandoColor();
}
public void draw(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(c1);
g2d.fillOval(x,y,50,50);
}
Random numGenerator = new Random();
private Color getRandoColor()
{
return new Color(numGenerator.nextInt(255), numGenerator.nextInt(255), numGenerator.nextInt(255));
}
public int getMinY(int y)
{minsy = y - 25; return minsy; }
public int getMaxY(int y)
{maxsy = y + 25; return maxsy; }
public int getMinX(int x)
{minsx = x - 25; return minsx; }
public int getMaxX(int x)
{maxsx = x + 25; return maxsx; }
}
#Override
protected void paintComponent(Graphics g)
{
//if (clickcount < 10)
{
super.paintComponent(g);
for (Circle cr : circles)
cr.draw(g);
}
}
public class MouseClicks implements MouseListener
{
int b, y, x ;
int circlecount;
public void mouseClicked(MouseEvent m)
{
int x = m.getX(), y = m.getY(); b = m.getButton();
this.x = x;
this.y = y;
if (b == 1 && circlecount < 10) //Left Click
{
circles.add(new Circle(x-25, y-25)); //x-40 and y - 75
RemoveCircle.this.repaint();
circlecount++;
}
if (b == 3) //Left Click
{ for (Circle c : circles)
{
if ((x >= c.getMinX(x) && x <= c.getMaxX(x)) && (y >= c.getMinY(y) && y <= c.getMaxY(y)))
{
circles.remove(c);
RemoveCircle.this.repaint();
circlecount--;
}
}
}
}
public void mouseExited(MouseEvent m) {}
public void mousePressed(MouseEvent m) {}
public void mouseEntered(MouseEvent m) {}
public void mouseReleased(MouseEvent m) {}
}
}
The easier approach would be to take advantage of the Shape interface. The shape could be a circle or rectangle etc. Then you can use the Shape.contains(...) method to determine if a mouse clicks is in the bounds of the shape.
So instead of create a Circle class you create a ShapeInfo class with two properties:
Shape
Color
Your store this object in your ArrayList and your painting logic now becomes something like:
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
for (ShapeInfo info : shapes)
{
g2d.setColor( info.getColor() );
g2d.draw( info.getShape() );
}
Then the code in your MouseListner will iterate through the same ArrayList and invoke the contains(...) method on each Shape. When you find a match you remove the entry from the ArrayList.
You can use the Ellipse2D.Double class for the circle shape. Check out the DrawOnComponent example found in Custom Painting Approaches for an example that draw rectangles using this basic approach.
I am tasked with how to paint an arrayList of shapes in java.
I feel i have most of it right, there are two methods i am confused about however
the method in ShapeChooserPanel called public void setPoints(int x, int y)
Since Xs and Ys are arrays, how would i set the x and y values?
And the other is one is the final method in ShapeChooserPanel I cannot find out how to print the Shapes in the array, It should paint the current shape at the place the mouse was clicked.
My code is below
Main class:
import javax.swing.JFrame;
public class Lab2 {
public static void main (String[] args) {
JFrame myFrame = new JFrame("Lab 2");
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.add(new ShapeChooserPanel());
myFrame.pack();
myFrame.setVisible(true);
}
}
ShapeChooserPanel class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.ArrayList;
public class ShapeChooserPanel extends JPanel {
private int currentX;
private int currentY;
private Color currentColor;
private int currentShape;
private JButton clearBtn;
private JRadioButton circle, square, triangle, box;
private DrawingPanel drawingPanel;
private JPanel controlsPanel;
//constants representing shape choice
private final int CIRCLE = 0;
private final int SQUARE = 1;
private final int TRIANGLE = 2;
private final int BOX = 3;
//constant delta used for setting distance between points
private final int DELTA = 25;
private int[] Xs;
private int[] Ys;
//store all the shapes to be painted UNCOMMENT when you have Shape.java defined
ArrayList<Shape> shapes;
public ShapeChooserPanel(){
//provide some default values paints a circle at (10,10) in blue
currentX = 10;
currentY = 10;
Xs = new int[4];//we will use all 4 points for the square, but only the first 3 for the triangle
Ys = new int[4];
setPoints(currentX,currentY);
currentShape = CIRCLE;
currentColor = Color.red;
shapes = new ArrayList<Shape>();
//instantiate the controls panel and set its layout to display everything in a single column
controlsPanel = new JPanel();
controlsPanel.setLayout(new BoxLayout(controlsPanel, BoxLayout.Y_AXIS));
//TODO: add clear button *
// TODO: define radio buttons *
clearBtn = new JButton("Clear");
clearBtn.addActionListener(new ClearListener());
circle = new JRadioButton("Red Circle");
circle.addActionListener(new ShapeListener());
square = new JRadioButton("Cyan Square");
square.addActionListener(new ShapeListener());
triangle = new JRadioButton("Green Triangle");
triangle.addActionListener(new ShapeListener());
box = new JRadioButton("Blue Box");
box.addActionListener(new ShapeListener());
ButtonGroup group = new ButtonGroup();
group.add(clearBtn);
group.add(circle);
group.add(square);
group.add(triangle);
group.add(box);
controlsPanel.add(clearBtn);
controlsPanel.add(circle);
controlsPanel.add(square);
controlsPanel.add(triangle);
controlsPanel.add(box);
//TODO: add radio buttons to group *
//TODO add listeners to radio buttons *
//TODO: add radio buttons to controls panel *
drawingPanel = new DrawingPanel();
drawingPanel.setBorder(BorderFactory.createLineBorder(Color.black));
//TODO: set a border around the drawing panel *
drawingPanel.setPreferredSize(new Dimension(200,200));
drawingPanel.addMouseListener(new PanelListener());
add(drawingPanel);
add(controlsPanel);
setPreferredSize(new Dimension (300,400));
}//end constructor
public void setPoints(int x, int y) {
//TODO: set Xs and Ys *
Xs[0] = x;
Ys[0] = y;
}
private class ClearListener implements ActionListener{
public void actionPerformed(ActionEvent ae){
shapes.removeAll(shapes);
drawingPanel.repaint();
}
}
private class PanelListener implements MouseListener {
public void mouseClicked(MouseEvent me) {
currentX = me.getX();
currentY = me.getY();
//TODO: find coordinates of this mouse click *
//TODO: add a new shape to the shapes list*
shapes.addAll(shapes);
setPoints(currentX, currentY);
//TODO: call setPoints with current x and y values *
drawingPanel.repaint();
}
public void mouseExited(MouseEvent me){}
public void mouseEntered(MouseEvent me){}
public void mouseReleased(MouseEvent me){}
public void mousePressed(MouseEvent me){}
}
//Class to listen for radio button changes
private class ShapeListener implements ActionListener{
public void actionPerformed(ActionEvent me){
//TODO: determine which radio button was clicked *
if(me.getSource() == circle){
currentShape = CIRCLE;
currentColor = Color.red;
}
if(me.getSource() == square){
currentShape = SQUARE;
currentColor = Color.cyan;
}
if(me.getSource() == triangle){
currentShape = TRIANGLE;
currentColor = Color.green;
}
if(me.getSource() == box){
currentShape = BOX;
currentColor = Color.blue;
}
//TODO: set current shape and color *
drawingPanel.repaint();
}
}
private class DrawingPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
//TODO: paint all the shapes in our list
}
}
}
and my Shape class
import java.awt.Color;
public class Shape {
private int x,y;
private int type;
private Color c;
public Shape(int x, int y, int type, Color c) {
this.x = x;
this.y = y;
this.type = type;
this.c = c;
}
public int x(int x) {
return x;
}
public int y(int y) {
return y;
}
public int type(int type) {
return type;
}
public Color c(Color c) {
return c;
}
}
super.paintComponent(g) invokes the paintComponent method from the superclass of JPanel (the JComponent class) to erase whatever is currently drawn on the panel. This is useful for animation, but not for setting color.
I guess you'll have to set the color of the shapes in your Arraylist<Shape> shapes when you will create them, nonetheless it could be helpfull to see the Shape class. Maybe you could create a function changeColor(Color ColorToBeSet) in this shape class and loop through the shapes ArrayList to call it at the end of your ShapeListener
You could...
Define an "abstract" concept of a shape, which has the basic properties (location and size) and which can paint itself...
public abstract class Shape {
private int x, y;
private int width, height;
private Color c;
public Shape(int x, int y, int width, int height, Color c) {
this.x = x;
this.y = y;
this.c = c;
this.width = width;
this.height = height;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return c;
}
public abstract void paint(Graphics2D g2d);
}
Then you can implement the individual shapes...
public class Rectangle extends Shape {
public Rectangle(int x, int y, int width, int height, Color c) {
super(x, y, width, height, c);
}
#Override
public void paint(Graphics2D g2d) {
g2d.setColor(getColor());
g2d.drawRect(getX(), getY(), getWidth(), getHeight());
}
}
public class Oval extends Shape {
public Oval(int x, int y, int width, int height, Color c) {
super(x, y, width, height, c);
}
#Override
public void paint(Graphics2D g2d) {
g2d.setColor(getColor());
g2d.drawOval(getX(), getY(), getWidth(), getHeight());
}
}
Then, you can simply call the paint method of each instance of Shape as required...
public class TestPane extends JPanel {
private List<Shape> shapes;
public TestPane() {
shapes = new ArrayList<>(25);
shapes.add(new Rectangle(10, 10, 20, 20, Color.RED));
shapes.add(new Oval(15, 15, 40, 20, Color.RED));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Shape shape : shapes) {
Graphics2D g2d = (Graphics2D) g.create();
shape.paint(g2d);
g2d.dispose();
}
}
}
Here i created a program. My main method create many shapes (boxes, triangles ...) I want to
have a button that if i click on it I can pick a color from large set of colors?
This is the main program ( with only the boxes):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Kaleidescope extends JFrame implements MouseListener, ActionListener, MouseMotionListener {
Box b;
Box[] boxes; // 2-d array of Box objects, form a color pallet
int boxCount;
JButton boxButton;
int x1, y1; // mousePressed
int w1, z1; // mouseEntered
int mode = 1; // 1 = line, 2= boxes, 3 = oval, 4= text, 5 = SG, twoLines = 7.
public static void main(String[] args) {
System.out.println("hi there.");
new Kaleidescope();
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(this);
addMouseMotionListener(this);
boxes = new Box[20];
boxCount = 0;
setLayout(new FlowLayout());
boxButton = new JButton("Boxes");
add(boxButton);
boxButton.addActionListener(this);
setSize(new Dimension(500, 500));
setVisible(true);
}
// returns a random color
public Color randomColor() {
int red = (int) (Math.random() * 255);
int green = (int) (Math.random() * 255);
int blue = (int) (Math.random() * 255);
return new Color(red, green, blue);
}
public void mouseClicked(MouseEvent e) {
System.out.println("click at x=" + e.getX() + " y=" + e.getY());
// convert window coords to box array indexes.
// These were adjusted slightly after the video was made
// (no more flakiness, these are right on target).
int boxi = (e.getX() - 10) / 20; // convert mouse x to box index
int boxj = (e.getY() - 40) / 20;
System.out.println("click at boxi=" + boxi + " boxj=" + boxj);
// set extra box to the color that we clicked on
if (mode == 2) {
boxes[boxCount++] = new Box(e.getX(), e.getY(), randomColor());
}
repaint();
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == boxButton) {
mode = 2;
repaint();
}
}
public void mouseEntered(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < boxCount; i++) {
boxes[i].drawMe(g);
}
}
}
This Is the other class for the box (connected to the main program to draw my box)
import java.awt.*;
public class Box {
protected Color color;
protected int x, y; // pixels from upper left to upper left corner
// make a box
public Box(int x1, int y1, Color c1) {
x = x1;
y = y1;
color = c1;
}
public void drawMe(Graphics g) {
g.setColor(color);
g.fillRect(x, y, 20, 20);
}
public void setColor(Color c) {
color = c;
}
public Color getColor() {
return color;
}
}
Here is another class
package kaleidescope;
public class Point {
int x;
int y;
public Point( int x1, int y1 ) {
x = x1; y = y1;
}
}
Also this class
package kaleidescope;
import java.awt.*;
public abstract class Shape {
protected Color color;
abstract public void drawMe( Graphics g );
}
What about the Java Color Chooser