Hey there i'm trying to design a GUI program ShapeFactory that has Buttons to produce :
a. Random Rectangles with random colors.
b. Random Ellipses with random colors.
c. Random Lines with random colors.
Whenever user clicks on a button, the corresponding shape will be added to the already drawn shapes in the JFrame.
and i'm stuck at trying to connect the ActionListener with the paint methode
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ShapeFactory extends JFrame implements ActionListener{
public static void main(String[] args) {
new ShapeFactory();
}
JButton ranRects = new JButton("Random Rectangles");
JButton ranElli = new JButton("Random Ellipses");
JButton ranLines = new JButton("Random Lines");
Graphics g;
Color c;
ArrayList shapeList = new ArrayList( );
public ShapeFactory(){
super("Shape Factory");
setLayout(new FlowLayout());
setSize(600,400);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
add(ranRects);
add(ranElli);
add(ranLines);
JPanel nPanel = new JPanel (new GridLayout(1,3));
nPanel.add(ranRects);
nPanel.add(ranElli);
nPanel.add(ranLines);
add(nPanel);
ranRects.addActionListener(this);
ranElli.addActionListener(this);
ranLines.addActionListener(this);
setVisible(true);
}
public void paint (Graphics g) {
super.paint(g);
if (d == 1) {
paintRect(g);
shapeList.add(d);
}
else if (d == 2) {
paintOval(g);
shapeList.add(d);
}
else if (d == 3 ) {
paintLine(g);
shapeList.add(d);
}
}
public void paintRect(Graphics g) {
int rectX1 = (int)(Math.random() * getWidth() / 4.0);
int rectY1 = (int)(Math.random() * getHeight()/ 4.0);
int rectX2 = (int)(Math.random() * getWidth());
int rectY2 = (int)(Math.random() * getHeight());
c = new Color( (int) (Math.random() * 255) , (int) (Math.random() * 255) , (int) (Math.random() * 255));
g.setColor(c);
g.fillRect(rectX1,rectY2,rectX2,rectY2);
}
public void paintOval(Graphics g) {
int ciX1 = (int)(Math.random() * getWidth() / 4.0);
int ciY1 = (int)(Math.random() * getHeight()/ 4.0);
int ciX2 = (int)(Math.random() * getWidth());
int ciY2 = (int)(Math.random() * getHeight());
c = new Color( (int) (Math.random() * 255) , (int) (Math.random() * 255) , (int) (Math.random() * 255));
g.setColor(c);
g.fillOval(ciX1,ciY1,ciX2,ciY2);
}
public void paintLine(Graphics g) {
int lineX1 = (int)(Math.random() * getWidth() / 4.0);
int lineY1 = (int)(Math.random() * getHeight()/ 4.0);
int lineX2 = (int)(Math.random() * getWidth());
int lineY2 = (int)(Math.random() * getHeight());
c = new Color( (int) (Math.random() * 255) , (int) (Math.random() * 255) , (int) (Math.random() * 255));
g.setColor(c);
g.drawLine(lineX1,lineY1,lineX2,lineY2);
}
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == ranRects) {
d = 1;
}
else if (source == ranElli) {
d = 2;
}
else if (source == ranLines) {
d = 3;
}
repaint();
}
}
So one solution would be to use 3 member variables to keep track of how many shapes of each type need to be drawn. Once a button is clicked you simply increment the corresponding variable and in the paint
method you call the paintOval
or whatever shape it is multiple times. In that case your paint
method could look like this:
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < this.numberOfRects; i++)
paintRect(g);
for (int i = 0; i < this.numberOfEllis; i++)
paintOval(g);
for (int i = 0; i < this.numberOfLines; i++)
this.paintLine(g);
}
And the actionPerformed
like this:
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == ranRects) {
this.numberOfRects++;
} else if (source == ranElli) {
this.numberOfEllis++;
} else if (source == ranLines) {
this.numberOfLines++;
}
repaint();
}
And you'd of course need to add the 3 member variables to the class.
If you want to store the shapes position and color I'd recommend to create a new class to store them in some sort of List
. You could create a inner class Shape
to store the shapes properties like position, size and color.
private class Shape{
public int x1;
public int y1;
public int x2;
public int y2;
public Color color;
}
You could then add member variables for each type of shape:
private List<Shape> rectList = new ArrayList<>();
private List<Shape> ovalList = new ArrayList<>();
private List<Shape> lineList = new ArrayList<>();
I would recommend a method to add a shape like this:
public void addRect(){
//Create new Shape
Shape shape = new Shape();
//Set shape's properties
shape.x1 = (int) (Math.random() * getWidth() / 4.0);
shape.x2 = (int) (Math.random() * getHeight() / 4.0);
shape.y1 = (int) (Math.random() * getWidth());
shape.y2 = (int) (Math.random() * getHeight());
shape.color = new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
//Add the shape to the list
this.rectList.add(shape);
}
and call the method in the actionListener
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == ranRects) {
addRect();
} else if (source == ranElli) {
addOval();
} else if (source == ranLines) {
addLine();
}
repaint();
}
To draw them you'd simply iterate the list for each type of shape:
public void paint(Graphics g) {
super.paint(g);
for (Shape s: rectList )
paintRect(g, s);
//...
//Add loops for all shapes
}
public void paintRect(Graphics g, Shape shape) {
g.setColor(shape.color);
g.fillRect(shape.x1, shape.y1, shape.x2, shape.y2);
}
At the end you should have something like this:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
public class ShapeFactory extends JFrame implements ActionListener {
public static void main(String[] args) {
new ShapeFactory();
}
JButton ranRects = new JButton("Random Rectangles");
JButton ranElli = new JButton("Random Ellipses");
JButton ranLines = new JButton("Random Lines");
private List<Shape> rectList = new ArrayList<>();
private List<Shape> ovalList = new ArrayList<>();
private List<Shape> lineList = new ArrayList<>();
private class Shape{
public int x1;
public int y1;
public int x2;
public int y2;
public Color color;
}
public ShapeFactory() {
super("Shape Factory");
setLayout(new FlowLayout());
setSize(600, 400);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
add(ranRects);
add(ranElli);
add(ranLines);
JPanel nPanel = new JPanel(new GridLayout(1, 3));
nPanel.add(ranRects);
nPanel.add(ranElli);
nPanel.add(ranLines);
add(nPanel);
ranRects.addActionListener(this);
ranElli.addActionListener(this);
ranLines.addActionListener(this);
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
for (Shape s: rectList )
paintRect(g, s);
//...
//Add loops for all shapes
}
public void paintRect(Graphics g, Shape shape) {
g.setColor(shape.color);
g.fillRect(shape.x1, shape.y1, shape.x2, shape.y2);
}
//...
//Add paint methods for oval and lines
public void addRect(){
//Create new Shape
Shape shape = new Shape();
//Set shape's properties
shape.x1 = (int) (Math.random() * getWidth() / 4.0);
shape.x2 = (int) (Math.random() * getHeight() / 4.0);
shape.y1 = (int) (Math.random() * getWidth());
shape.y2 = (int) (Math.random() * getHeight());
shape.color = new Color((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255));
//Add the shape to the list
this.rectList.add(shape);
}
//...
//Add methods to add ovals and lines
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == ranRects) {
addRect();
} else if (source == ranElli) {
//addOval();
} else if (source == ranLines) {
//addLine();
}
repaint();
}
}
I've only implemented the paint
and add
methods for rectangles but it wouldn't be hard to add ovals and lines.
Hope this helped