The stickman is connected to the bubble by a line. When I move for example, Jimmy, I want the line that connects Jimmy to the Fruits he sells to be maintained. The same goes when I drag Fruit.
But somehow this is not working. When I drag the stickman or the bubble, the lines got disjointed.
Here are my codes if anyone would like to try and run it. I've tried to include only the relevant stuffs.
Example class
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JPanel {
private static List<Person> persons;
private static List<Fruit> fruits;
private static List<LineTest> lines;
private Point mousePt;
private static Font setFont;
private Random randomGenerator;
private Person person;
private Fruit bubble;
private LineTest line;
private static final int W = 640;
private static final int H = 480;
public Example() {
persons = new ArrayList<Person>(); // Stores the person's names & coords
fruits = new ArrayList<Fruit>(); // Stores the person's name and what fruits he sells & coords
lines = new ArrayList<LineTest>(); // Stores the person's name, fruits he sells & coords
randomGenerator = new Random();
setFont = new Font("Sans Serif", Font.BOLD, 12);
String person1 = "Jimmy";
String person2 = "Sally";
person = new Person(person1, 50,50);
addPerson(person);
person = new Person(person2, 50,150);
addPerson(person);
String fruit1 = "Banana";
String fruit2 = "Apple";
String fruit3 = "Orange";
String fruit4 = "Watermelon";
String fruit5 = "Pineapple";
String fruit6 = "Grapes";
bubble = new Fruit(person1, fruit1, setFont, 150, 50);
addFruit(bubble);
bubble = new Fruit(person1, fruit2, setFont, 150, 100);
addFruit(bubble);
bubble = new Fruit(person1, fruit3, setFont, 150, 150);
addFruit(bubble);
bubble = new Fruit(person2, fruit4, setFont, 150, 200);
addFruit(bubble);
bubble = new Fruit(person2, fruit5, setFont, 150, 250);
addFruit(bubble);
bubble = new Fruit(person2, fruit6, setFont, 150, 300);
addFruit(bubble);
for (int i=0; i<persons.size();i++) {
for (int j=0; j<fruits.size();j++) {
// If the same person in the person's list can be found in the fruits list
// draw a line between the Person and the Fruit
if (persons.get(i).getPerson().equals((fruits.get(j).getPerson()))) {
int personX = persons.get(i).getCoorX();
int personY = persons.get(i).getCoorY();
int fruitX = fruits.get(j).getCoorX();
int fruitY = fruits.get(j).getCoorY();
line = new LineTest(persons.get(i).getPerson(), fruits.get(j).getFruit(), personX, personY, fruitX, fruitY);
addLine(line);
}
}
}
this.setFont(setFont);
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
mousePt = e.getPoint();
for (Person p:persons) {
p.select(mousePt.x, mousePt.y);
}
for (Fruit f:fruits) {
f.select(mousePt.x, mousePt.y);
}
}
public void mouseReleased(MouseEvent e) {
for (Person p:persons) {
p.unselect();
}
for(Fruit f:fruits) {
f.unselect();
}
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
mousePt = e.getPoint();
for (Person s:persons) {
s.move(mousePt.x, mousePt.y);
int personX = mousePt.x;
int personY = mousePt.y;
for(int k=0; k<lines.size(); k++) {
// If the same person in the person's list can be found in the fruits list
// move the point on the Person to a new coords
if(s.person.equals(lines.get(k).person)) {
lines.get(k).move(personX, personY);
}
}
}
for(Fruit f:fruits) {
f.move(mousePt.x, mousePt.y);
int fruitX = mousePt.x;
int fruitY = mousePt.y;
for(int k=0; k<lines.size(); k++) {
if(f.person.equals(lines.get(k).person)) {
lines.get(k).move(fruitX, fruitY);
}
}
}
repaint();
}
});
}
public void addPerson(Person person) {
persons.add(person);
repaint();
}
public void addFruit (Fruit fruit) {
fruits.add(fruit);
repaint();
}
public void addLine(LineTest line) {
lines.add(line);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
for (Person p:persons) {
p.paint(g2);
}
for (LineTest l:lines) {
l.paint(g2);
}
for (Fruit f:fruits) {
f.paint(g2);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.add(new Example());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
Person class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
public class Person extends Rectangle {
String person;
int x,y;
int tx, ty;
boolean isSelected = false;
public Person(String person, int x, int y) {
this.person = person;
this.x = x;
this.y = y;
this.setBounds(x-10,y-10,40,90);
isSelected = true;
move(x, y);
isSelected = false;
}
public void select(int x, int y){
if(this.contains(x,y)) {
isSelected=true;
}
}
public void unselect(){
isSelected = false;
}
public void move(int x, int y) {
if(isSelected) {
LineTest.isPersonMoved = true;
LineTest.isFruitMoved = false;
tx = x;
ty= y;
this.translate(tx-this.x, ty-this.y);
this.x = tx;
this.y = ty;
}
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawOval(x, y, 20, 20); // head
g2.drawLine(x+10,y+20,x+10,y+50); // body
g2.drawLine(x+10,y+20,x+25,y+40); // right hand
g2.drawLine(x+10,y+20,x-5,y+40); // left hand
g2.drawLine(x+10,y+50,x-5,y+70); // left leg
g2.drawLine(x+10,y+50,x+25,y+70); // right leg
g2.drawString(person, tx-15, ty+85);
}
public String getPerson() {
return person;
}
public int getCoorX() {
return x;
}
public int getCoorY() {
return y;
}
}
Fruit class
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
public class Fruit extends Rectangle {
private static final long serialVersionUID = 1L;
String fruit, person;
Font _font;
int x, y, tx, ty;
public static int height, width, ovalWidth, ovalHeight;
boolean isSelected;
public static FontMetrics getMetrics;
public static Graphics2D g2;
public Fruit(String person, String fruit, Font font, int x, int y) {
this.person = person;
this.fruit = fruit;
this._font = font;
this.x = x;
this.y = y;
this.setBounds(x, y, ovalWidth, ovalHeight);
isSelected = true;
move(x, y);
isSelected = false;
}
public void select(int x, int y){
if(this.contains(x,y)) {
isSelected=true;
}
}
public void unselect(){
isSelected = false;
}
public void move(int x, int y) {
if(isSelected) {
LineTest.isPersonMoved = false;
LineTest.isFruitMoved = true;
tx = x;
ty= y;
this.translate(tx-this.x, ty-this.y);
this.x = tx;
this.y = ty;
}
}
public void paint(Graphics g) {
g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
getMetrics = g2.getFontMetrics(_font);
height = getMetrics.getHeight();
width = getMetrics.stringWidth(fruit);
ovalWidth = width+25;
ovalHeight = height+25;
g2.setColor(Color.WHITE);
g2.fillOval(x, y, ovalWidth, ovalHeight);
g2.setColor(Color.BLACK);
g2.drawOval(x, y, ovalWidth, ovalHeight);
int centreX = x + ovalWidth/2;
int centreY = y + ovalHeight/2;
g2.drawString(fruit, (int) (centreX - width/2), (int) (centreY + height/4));
this.setBounds(x, y, ovalWidth, ovalHeight);
}
public String getPerson() {
return person;
}
public String getFruit() {
return fruit;
}
public int getCoorX() {
return x;
}
public int getCoorY() {
return y;
}
}
LineTest class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
/*
* Draw line that connect between Person and Fruit
*/
public class LineTest {
int x1, y1, x2, y2, tx, ty;
String fruit, person;
public static boolean isPersonMoved, isFruitMoved;
public LineTest(String person, String fruit, int x1, int y1, int x2, int y2) {
this.person = person;
this.fruit = fruit;
// Get x, y coordinates from person bound
this.x1 = x1+35;
this.y1 = y1+35;
// Get x, y coordinates from fruit bound
this.x2 = x2+30;
this.y2 = y2+30;
}
public void move(int x, int y) {
if (isPersonMoved) {
System.out.println("LineTest - isPersonMoved: " + isPersonMoved);
tx = x;
ty = y;
this.x1 = tx+35;
this.y1 = ty+35;
} else if (isFruitMoved) {
System.out.println("LineTest - isFruitMoved: " + isFruitMoved);
tx = x;
ty = y;
this.x2 = tx+30;
this.y2 = ty+30;
}
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawLine(x1, y1, x2, y2);
}
public String getPerson() {
return person;
}
public String getFruit() {
return fruit;
}
public Point getFstCoor() {
return new Point (x1, y1);
}
public Point getSndCoor() {
return new Point(x2, y2);
}
}
The basic idea is, you need to generate some kind of relationship between the objects you want to link. You could make this relationship implicit (Person contains Fruit) or non-implicit, where the relationship is stored/managed externally, which you do is up to you (I like the implicit approach as it sets out your intentions)
Your codes a bit, odd, sorry, but it is, so I've made some modifications. I did think of using a Path2D for a lot of it, but that would mean everything code painted in the same color. The main point is to define some kind of commonality between the objects, while strictly speaking not required, because almost all the work between them is the same, why not...
public interface Paintable {
public void paint(JComponent parent, Graphics2D g2d);
public boolean contains(Point p);
public void moveTo(Point2D p);
public Rectangle2D getBounds();
}
Then I created a class to manage the relationships...
public class Relationship {
private Paintable parent;
private Paintable child;
public Relationship(Paintable parent, Paintable child) {
this.parent = parent;
this.child = child;
}
public Paintable getChild() {
return child;
}
public Paintable getParent() {
return parent;
}
}
Now, this means that your fruits could belong to more then one person (or other fruits), so if this goes against your rules, you will need to devise a different relationship algorithm (maybe something more implicit)
Now, when ever you update the UI, you simply paint the relationships and the objects...
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
for (Relationship relationship : relationships) {
Point2D p1 = new Point2D.Double(relationship.getParent().getBounds().getCenterX(), relationship.getParent().getBounds().getCenterY());
Point2D p2 = new Point2D.Double(relationship.getChild().getBounds().getCenterX(), relationship.getChild().getBounds().getCenterY());
g2.draw(new Line2D.Double(p1, p2));
}
for (Person p : persons) {
p.paint(this, g2);
}
for (Fruit f : fruits) {
f.paint(this, g2);
}
g2.dispose();
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JPanel {
private List<Person> persons;
private List<Fruit> fruits;
private Point2D offset;
private static Font baseFont;
private Random randomGenerator;
private Person person;
private Fruit bubble;
private static final int W = 640;
private static final int H = 480;
private Paintable selectedShape;
private List<Relationship> relationships;
public Example() {
persons = new ArrayList<>(); // Stores the person's names & coords
fruits = new ArrayList<>(); // Stores the person's name and what fruits he sells & coords
relationships = new ArrayList<>(25);
randomGenerator = new Random();
baseFont = new Font("Sans Serif", Font.BOLD, 12);
String person1 = "Jimmy";
String person2 = "Sally";
String fruit1 = "Banana";
String fruit2 = "Apple";
String fruit3 = "Orange";
String fruit4 = "Watermelon";
String fruit5 = "Pineapple";
String fruit6 = "Grapes";
Person person = new Person(person1, 50, 50);
addPerson(person);
Fruit bubble = new Fruit(fruit1, baseFont, 150, 50);
addFruit(bubble);
relate(person, bubble);
bubble = new Fruit(fruit2, baseFont, 150, 100);
addFruit(bubble);
relate(person, bubble);
bubble = new Fruit(fruit3, baseFont, 150, 150);
addFruit(bubble);
relate(person, bubble);
person = new Person(person2, 50, 150);
addPerson(person);
bubble = new Fruit(fruit4, baseFont, 150, 200);
addFruit(bubble);
relate(person, bubble);
bubble = new Fruit(fruit5, baseFont, 150, 250);
addFruit(bubble);
relate(person, bubble);
bubble = new Fruit(fruit6, baseFont, 150, 300);
addFruit(bubble);
relate(person, bubble);
this.setFont(baseFont);
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
for (Paintable p : getShapes()) {
if (p.contains(e.getPoint())) {
// Selected
selectedShape = p;
offset = new Point2D.Double(e.getX() - p.getBounds().getX(), e.getY() - p.getBounds().getY());
break;
}
}
}
public void mouseReleased(MouseEvent e) {
selectedShape = null;
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (selectedShape != null) {
Point2D p = new Point2D.Double(e.getX() - offset.getX(), e.getY() - offset.getX());
selectedShape.moveTo(p);
}
repaint();
}
});
}
protected List<Paintable> getShapes() {
ArrayList<Paintable> shapes = new ArrayList<>(fruits);
shapes.addAll(persons);
return shapes;
}
public void addPerson(Person person) {
persons.add(person);
repaint();
}
public void addFruit(Fruit fruit) {
fruits.add(fruit);
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
for (Relationship relationship : relationships) {
Point2D p1 = new Point2D.Double(relationship.getParent().getBounds().getCenterX(), relationship.getParent().getBounds().getCenterY());
Point2D p2 = new Point2D.Double(relationship.getChild().getBounds().getCenterX(), relationship.getChild().getBounds().getCenterY());
g2.draw(new Line2D.Double(p1, p2));
}
for (Person p : persons) {
p.paint(this, g2);
}
for (Fruit f : fruits) {
f.paint(this, g2);
}
g2.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, H);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
f.add(new Example());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
protected void relate(Person person, Fruit bubble) {
relationships.add(new Relationship(person, bubble));
}
public class Relationship {
private Paintable parent;
private Paintable child;
public Relationship(Paintable parent, Paintable child) {
this.parent = parent;
this.child = child;
}
public Paintable getChild() {
return child;
}
public Paintable getParent() {
return parent;
}
}
public interface Paintable {
public void paint(JComponent parent, Graphics2D g2d);
public boolean contains(Point p);
public void moveTo(Point2D p);
public Rectangle2D getBounds();
}
public class Fruit implements Paintable {
private static final long serialVersionUID = 1L;
String fruit;
Font font;
private Ellipse2D bounds;
public Fruit(String fruit, Font font, int x, int y) {
this.fruit = fruit;
this.font = font;
bounds = new Ellipse2D.Double(x, y, 40, 90);
}
public String getFruit() {
return fruit;
}
#Override
public boolean contains(Point p) {
return bounds.contains(p);
}
#Override
public void moveTo(Point2D p) {
bounds = new Ellipse2D.Double(p.getX(), p.getY(), 40, 90);
}
#Override
public void paint(JComponent parent, Graphics2D g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(font);
FontMetrics fm = g2.getFontMetrics();
int height = fm.getHeight();
int width = fm.stringWidth(fruit);
g2.setColor(Color.WHITE);
g2.fill(bounds);
g2.setColor(Color.BLACK);
g2.draw(bounds);
double centreX = bounds.getX() + bounds.getWidth() / 2d;
double centreY = bounds.getY() + bounds.getHeight() / 2d;
g2.drawString(fruit, (int) (centreX - width / 2), (int) (centreY + height / 4));
g2.dispose();
}
#Override
public Rectangle2D getBounds() {
return bounds.getBounds2D();
}
}
public class Person implements Paintable {
String person;
private Rectangle2D bounds;
public Person(String person, int x, int y) {
this.person = person;
bounds = new Rectangle2D.Double(x, y, 40, 90);
}
#Override
public void paint(JComponent parent, Graphics2D g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(bounds.getX(), bounds.getY());
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawOval(0, 0, 20, 20); // head
g2.drawLine(10, 20, 10, 50); // bodbounds.getY()
g2.drawLine(10, 20, 25, 40); // right hand
g2.drawLine(10, 20, 0 - 5, 40); // left hand
g2.drawLine(10, 50, 0 - 5, 70); // left leg
g2.drawLine(10, 50, 25, 70); // right leg
g2.drawString(person, 0 - 15, 85);
g2.dispose();
}
public String getPerson() {
return person;
}
#Override
public boolean contains(Point p) {
return bounds.contains(p);
}
#Override
public void moveTo(Point2D p) {
bounds = new Rectangle2D.Double(p.getX(), p.getY(), 40, 90);
}
#Override
public Rectangle2D getBounds() {
return bounds.getBounds2D();
}
}
}
I would encourage you to have a look at Path2D, at least for the stick figure, it will make life eaiser
Save the positions of a the stick man within itself and the position of the fruits within their objects. Relate each objects which are together. When a repaint() is started get the position information of the stick man and the position information of the fruit and draw a line between these two points. If a move is done then a repaint of the line should done also.
Related
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.border.BevelBorder;
public class Cliente extends JPanel {
private JButton adelanteButton;
private JButton undoButton;
private JPanel panel1;
private JPanel panelDibujo;
private Rectangulo rectangulo = new Rectangulo();
Originator originator;
Caretaker caretaker;
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Patron Memento");
Cliente cliente = new Cliente();
frame.setContentPane(cliente.panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Memento m : caretaker.history) {
System.out.println("forcitooooooo");
dibujar(m.getState(), Color.GREEN);
}
}
public Cliente() {
caretaker = new Caretaker();
originator = new Originator();
createUIComponents();
undoButton.addActionListener(e -> {
caretaker.anterior();
panelDibujo.repaint();
});
panelDibujo.setBackground(Color.WHITE);
panelDibujo.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
panelDibujo.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
MousePressedEvent(e);
}
#Override
public void mouseReleased(MouseEvent e) {
MouseReleasedEvent(e);
}
});
}
private void createUIComponents() {
}
private void MousePressedEvent(MouseEvent e){
rectangulo.setX1(e.getX());
rectangulo.setY1(e.getY());
}
private void MouseReleasedEvent(MouseEvent e){
rectangulo.setX2(e.getX());
rectangulo.setY2(e.getY());
originator.setState(rectangulo);
dibujar(rectangulo, Color.orange);
caretaker.addMemento(originator.CreateMemento());
rectangulo = new Rectangulo();
}
public void dibujar(Rectangulo r, Color c) {
Graphics g = panelDibujo.getGraphics();
g.setColor(c);
g.drawRect(r.getX1(), r.getY1(), r.getX2() - r.getX1(), r.getY2() - r.getY1());
g.dispose();
}
}
Hello i am applying the memento pattern by using a jpanel and drawing some rectangles inside, right now my code is working fine about drawing with the mouse events, but the issue is when i try to undo. My logic so far is clear the jpanel and redo all the rectangles minus the last one.
But after clearing my jpanel is not drawing again :( can someone help me to fix it? thank you
Caretaker.java
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
public class Caretaker {
LinkedList<Memento> history;
int indice;
public Caretaker(){
history = new LinkedList<>();
indice = 0;
}
void addMemento(Memento m){
if (history.size() == indice || history.isEmpty()){
indice++;
history.add(m);
}else {
indice = history.size()-1;
history.subList(indice +1, history.size()).clear();
}
}
Memento anterior(){
if (history.size() > 0){
indice--;
return history.removeLast();
}
JOptionPane.showMessageDialog(null, "No hay mas wey!");
return null;
}
Memento siguiente(){
if (indice < history.size()+1){
indice++;
return history.get(indice+1);
}
JOptionPane.showMessageDialog(null, "No hay mas wey!");
return null;
}
public void redibujar(JPanel f){
Graphics g = f.getGraphics();
for (Memento m: history) {
g.drawRect(m.getState().getX1(), m.getState().getY1(), m.getState().getX2() - m.getState().getX1(), m.getState().getY2() - m.getState().getY1());
g.dispose();
}
}
public void clear(){
history.clear();
indice = 0;
}
}
Memento.java
public class Memento {
Rectangulo state;
/*
Constructor, unica manera de mandar/crear/guardar los datos
*/
public Memento(Rectangulo state) {
this.state = state;
}
public Memento(){
state = new Rectangulo();
}
Rectangulo getState(){
return state;
}
}
Originator.java
public class Originator {
Rectangulo state;
public void setState(Rectangulo rectangulo){
this.state = rectangulo;
}
public Memento CreateMemento(){
return new Memento(state);
}
public void setMemento(Memento m) {
setState(m.getState());
}
}
Rectangulo.java
import java.awt.*;
public class Rectangulo {
private int x1;
private int x2;
private int y1;
private int y2;
Rectangulo(){
}
public Rectangulo(int x1, int x2, int y1, int y2) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public int getX2() {
return x2;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int getY1() {
return y1;
}
public void setY1(int y1) {
this.y1 = y1;
}
public int getY2() {
return y2;
}
public void setY2(int y2) {
this.y2 = y2;
}
public void draw(Graphics g){
g.setColor(Color.orange);
g.drawRect(this.getX1(), this.getY1(), this.getX2() - this.getX1(), this.getY2() - this.getY1());
}
}
Again, you're not drawing correctly. You are trying to render using a JPanel, cliente, that is never added to the GUI, and you're trying to use a Graphics object that is extracted from this unrendered component, making the Graphics object thus obtained short-lived and unstable.
Instead, do all drawing in the paintComponent method. You can use a BufferedImage and draw that in paintComponent if desired, especially if you want images with objects that show different colors, or you can use your List (here a LinkedList, but ArrayList will work) and draw in paintComponent. For instance, something simple like:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class Cliente2 extends JPanel {
private static final int BI_WIDTH = 800;
private static final int BI_HEIGHT = 650;
private Rectangle drawingRect = null;
// private java.util.List<Rectangulo> rectangulos = new ArrayList<>();
List<Rectangulo2> rectangulos = new ArrayList<>();
private JButton clearBtn = new JButton("Clear");
public Cliente2() {
setBackground(Color.WHITE);
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
clearBtn.addActionListener(e -> clear());
add(clearBtn);
}
private void clear() {
rectangulos.clear();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BI_WIDTH, BI_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (drawingRect != null) {
g2.setColor(Color.LIGHT_GRAY);
g2.draw(drawingRect);
}
for (Rectangulo2 rectangulo : rectangulos) {
rectangulo.draw(g2);
}
}
private class MyMouse extends MouseAdapter {
private Point p0;
#Override
public void mousePressed(MouseEvent e) {
p0 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
drawingRect = createDrawingRect(e);
repaint();
}
private Rectangle createDrawingRect(MouseEvent e) {
Point p1 = e.getPoint();
int x = Math.min(p0.x, p1.x);
int y = Math.min(p0.y, p1.y);
int width = Math.abs(p0.x - p1.x);
int height = Math.abs(p0.y - p1.y);
return new Rectangle(x, y, width, height);
}
#Override
public void mouseReleased(MouseEvent e) {
// lets create some random colors:
float hue = (float) Math.random();
float brightness = (float) Math.random();
Color color = Color.getHSBColor(hue, 1f, brightness);
Rectangulo2 rectangulo = new Rectangulo2(color, p0, e.getPoint());
rectangulos.add(rectangulo);
drawingRect = null;
repaint();
}
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Patron Memento");
// Cliente cliente = new Cliente();
// frame.setContentPane(cliente.panel1);
frame.add(new Cliente2());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
class Rectangulo2 {
private static final Stroke STROKE = new BasicStroke(3f);
private Color color;
private Point p0, p1;
public Rectangulo2() {
}
public Rectangulo2(Color color, Point p0, Point p1) {
super();
this.color = color;
this.p0 = p0;
this.p1 = p1;
}
public Color getColor() {
return color;
}
public Point getP0() {
return p0;
}
public Point getP1() {
return p1;
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(color);
int x = Math.min(p0.x, p1.x);
int y = Math.min(p0.y, p1.y);
int width = Math.abs(p0.x - p1.x);
int height = Math.abs(p0.y - p1.y);
g2.fillRect(x, y, width, height);
g2.setStroke(STROKE);
g2.setColor(Color.BLACK);
g2.drawRect(x, y, width, height);
g2.dispose();
}
}
So I'm new at java and need some help with my breakout game. My JFrame is just blank and i don't know how to fix it?
So I have a ball class, paddle class, canvas class and a brick class as well as a main class. In my canvas class I set all functions the ball, paddle and bricks has etc. In brick class I draw the bricks. And in my main I do the JFrame but it's blank
Main class :
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame();
Canvas c = new Canvas();
frame.add(c);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I expect the JFrame to show the game instead of just blank window
package breakout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.KeyEvent;
import breakout.Bricks.Type;
public class Canvas extends JPanel implements ActionListener, MouseMotionListener, MouseListener, KeyListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int HEIGHT = 600;
public static final int WIDTH = 720;
private int horizontalCount;
private BufferedImage image;
private Graphics2D bufferedGraphics;
private Timer time;
private static final Font endFont = new Font(Font.SANS_SERIF, Font.BOLD, 20);
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private Paddle player;
private Ball ball;
ArrayList<ArrayList<Bricks>> bricks;
public Canvas() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
bufferedGraphics = image.createGraphics();
time = new Timer (15, this);
player = new Paddle((WIDTH/2)-(Paddle.PADDLE_WIDTH/2));
ball = new Ball (((player.getX() + (Paddle.PADDLE_WIDTH / 2 )) - (Ball.DIAMETER / 2)), (Paddle.Y_POS - (Ball.DIAMETER + 10 )), -5, -5);
bricks = new ArrayList<ArrayList<Bricks>>();
horizontalCount = WIDTH / Bricks.BRICK_WIDTH;
for(int i = 0; i < 8; ++i) {
ArrayList<Bricks> temp = new ArrayList<Bricks>();
#SuppressWarnings("unused")
Type rowColor = null;
switch(i) {
case 0 :
case 2:
rowColor = Type.LOW;
break;
case 1 :
case 3 :
case 5 :
rowColor = Type.MEDIUM;
break;
case 4 :
case 6 :
rowColor = Type.HIGH;
break;
case 7 :
default :
rowColor = Type.ULTRA;
break;
}
for(int j = 0; j < horizontalCount; ++j) {
Bricks tempBrick = new Bricks();
temp.add(tempBrick);
}
bricks.add(temp);
addMouseMotionListener(this);
addMouseListener(this);
addKeyListener(this);
requestFocus();
}
}
public void actionPerformed(ActionEvent e) {
checkCollisions();
ball.Move();
for(int i = 0; i < bricks.size(); ++i) {
ArrayList<Bricks> al = bricks.get(i);
for(int j = 0; j < al.size(); ++j) {
Bricks b = al.get(j);
if(b.dead()) {
al.remove(b);
}
}
}
repaint();
}
private void checkCollisions() {
if(player.hitPaddle(ball)) {
ball.setDY(ball.getDY() * -1);
return;
}
if(ball.getX() >= (WIDTH - Ball.DIAMETER) || ball.getX() <= 0) {
ball.setDX(ball.getDX() * -1);
}
if(ball.getY() > (Paddle.Y_POS + Paddle.PADDLE_HEIGHT + 10)) {
resetBall();
}
if(ball.getY() <= 0) {
ball.setDY(ball.getDY() * -1);
}
int brickRowActive = 0;
for(ArrayList<Bricks> alb : bricks) {
if(alb.size() == horizontalCount) {
++brickRowActive;
}
}
for(int i = (brickRowActive==0) ? 0 : (brickRowActive - 1); i < bricks.size(); ++i) {
for(Bricks b : bricks.get(i)) {
if(b.hitBy(ball)) {
player.setScore(player.getScore() + b.getBrickType().getPoints());
b.decrementType();
}
}
}
}
private void resetBall() {
if(gameOver()) {
time.stop();
return;
}
ball.setX(WIDTH/2);
ball.setDY((HEIGHT/2) + 80);
player.setLives(player.getLives() -1);
player.setScore(player.getScore() <= 1);
}
private boolean gameOver() {
if(player.getLives() <= 1) {
return true;
}
return false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
bufferedGraphics.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(bufferedGraphics);
player.drawBall(bufferedGraphics);
for(ArrayList<Bricks> row : bricks) {
for(Bricks b : row) {
b.drawBrick(bufferedGraphics);
}
}
bufferedGraphics.setFont(scoreFont);
bufferedGraphics.drawString("Score: " + player.getScore(), 10, 25);
if(gameOver() && ball.getY() >= HEIGHT) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("Game Over Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT/2));
}
if(empty()) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("You won. Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT /2));
time.stop();
}
g.drawImage(image, 0, 0, this);
Toolkit.getDefaultToolkit().sync();
}
private boolean empty() {
for(ArrayList<Bricks> al : bricks) {
if(al.size() != 0) {
return false;
}
}
return true;
}
#Override
public void mouseMoved(MouseEvent e) {
player.setX(e.getX() - (Paddle.PADDLE_WIDTH / 2));
}
#Override
public void mouseClicked(MouseEvent e) {
if(time.isRunning()) {
return;
}
time.start();
}
#Override
public void mouseDragged(MouseEvent e) { }
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
#Override
public void keyPressed(KeyEvent arg0) {}
#Override
public void keyReleased(KeyEvent arg0) {}
#Override
public void keyTyped(KeyEvent arg0) {}
}
Preparing an MCVE, as required in SO, not only it makes helping much easier.
In many case, while preparing one, you are likely to find the problem, so it is a good debugging tool.
To answer "why is my JFrame blank ?" you could create the minimal code example like the following (copy-paste the entire code into GameBoard.java and run):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameBoard extends JPanel {
static final int HEIGHT = 600, WIDTH = 720, BRICK_ROWS = 8;
private final int horizontalCount;
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private final Paddle player;
private final Ball ball;
ArrayList<ArrayList<Brick>> bricks;
public GameBoard() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
player = new Paddle(WIDTH/2-Paddle.PADDLE_WIDTH/2);
ball = new Ball (player.getX() + Paddle.PADDLE_WIDTH / 2 - Ball.DIAMETER / 2,
Paddle.Y_POS - (Ball.DIAMETER + 10 ));
bricks = new ArrayList<>();
horizontalCount = WIDTH / Brick.BRICK_WIDTH;
for(int i = 0; i < BRICK_ROWS; ++i) {
ArrayList<Brick> temp = new ArrayList<>();
for(int j = 0; j < horizontalCount; ++j) {
Brick tempBrick = new Brick(j*Brick.BRICK_WIDTH , Brick.BRICK_YPOS + i*Brick.BRICK_HEIGHT);
temp.add(tempBrick);
}
bricks.add(temp);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
g2D.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(g2D);
ball.drawBall(g2D);
for(ArrayList<Brick> row : bricks) {
for(Brick b : row) {
b.drawBrick(g2D);
}
}
g2D.setFont(scoreFont);
g2D.drawString("Score: " + player.getScore(), 10, 25);
}
}
class Paddle{
public final static int PADDLE_WIDTH = 100, PADDLE_HEIGHT= 30, Y_POS = GameBoard.HEIGHT - 2* PADDLE_HEIGHT;
private int xPos, score;
Paddle(int xPos) {
this.xPos = xPos;
}
void setX(int xPos) {this.xPos = xPos;}
int getX() {return xPos;}
String getScore() {
return String.valueOf(score);
}
void drawPaddle(Graphics2D g2D) {
g2D.setColor(Color.GREEN);
g2D.fillRect(xPos, Y_POS, PADDLE_WIDTH, PADDLE_HEIGHT);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(400,250);
frame.add(new GameBoard());
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
class Brick{
final static int BRICK_WIDTH = 80, BRICK_HEIGHT = 15, BRICK_YPOS = 50;
int xPos, yPos;
Brick(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBrick(Graphics2D g2D) {
g2D.setColor(Color.RED);
g2D.fillRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
g2D.setColor(Color.BLACK);
g2D.drawRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
}
}
class Ball{
final static int DIAMETER = 40;
int xPos, yPos;
Ball(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBall(Graphics2D g2D) {
g2D.setColor(Color.BLUE);
g2D.fillOval(xPos, yPos, DIAMETER, DIAMETER);
}
}
This produces the following result, which I believe can serve as the basis of what you wanted to achieve:
Now start adding the missing functionality and see what breaks it.
I want to draw circle only after mouse gets click. As paintComponent method called itself, so first circle draw without click.
public class DrawPanel extends JPanel implements MouseListener {
private static final long serialVersionUID = 1L;
int x, y;
public DrawPanel() {
setBackground(Color.WHITE);
addMouseListener(this);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.fillOval(x, y, 20, 20);
}
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
}
There are a few issues with your code:
You never call super.paintComponent();
You only have one x and y
Note how when you resize the frame, some circles will disappear and it overall behaves in a strange way.
I would store all the Points where the user has clicked in an ArrayList and then loop through that list inside the paintComponent method. This way you can call super.paintComponent(); without the circles disappearing.
Changed, working code:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawPanel extends JPanel {
private static final long serialVersionUID = 1L;
private ArrayList<Point> points;
public DrawPanel() {
points = new ArrayList<Point>();
setBackground(Color.WHITE);
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
points.add(new Point(e.getX(), e.getY()));
repaint();
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.red);
for (Point point : points) {
g2.fillOval(point.x, point.y, 20, 20);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new DrawPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
});
}
}
You should place your circle inside its own class. That class will hold information on its location, radius, and its color. You can abstract your shape and have a list of shapes to draw on the panel. This will make it easy to implement a triangle, square, hexagon, etc. later.
You can add more methods and attributes to your shape objects later and only have to change their internal implementation of THEIR OWN paintComponent(g) method. This makes the DrawPanel depend on how each Shape does its own drawing.
App.java
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class App {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Circle Click Application");
DrawPanel p = new DrawPanel(10f);
p.setPreferredSize(new Dimension(300, 200));;
f.setContentPane(p);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
DrawPanel.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class DrawPanel extends JPanel implements MouseListener {
private static final long serialVersionUID = -6817035652787391530L;
private List<Shape> shapes;
protected float radius;
private float sat = 0.7f;
private float bri = 0.8f;
public DrawPanel(float radius) {
this.shapes = new ArrayList<Shape>();
this.radius = radius;
setBackground(Color.WHITE);
addMouseListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Shape shape : shapes) {
shape.paintComponent(g);
}
}
#Override
public void mouseClicked(MouseEvent e) {
shapes.add(new Circle(e.getX(), e.getY(), radius, ColorUtils.randHue(sat, bri)));
repaint();
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(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
}
}
Shape.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public interface Shape {
Point getOrigin();
void setOrigin(Point origin);
Color getColor();
void setColor(Color color);
void paintComponent(Graphics g);
}
Circle.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Circle implements Shape {
private Point origin;
private float radius;
private Color color;
public Circle() {
this(0, 0, 0.5f, Color.BLACK);
}
public Circle(int x, int y, float radius, Color color) {
this(new Point(x, y), radius, color);
}
public Circle(Point origin, float radius, Color color) {
this.origin = origin;
this.radius = radius;
this.color = color;
}
#Override
public Point getOrigin() {
return origin;
}
#Override
public void setOrigin(Point origin) {
this.origin = origin;
}
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
}
#Override
public Color getColor() {
return color;
}
#Override
public void setColor(Color color) {
this.color = color;
}
#Override
public void paintComponent(Graphics g) {
int diameter = (int) (this.radius * 2);
int x = (int) (origin.x - this.radius);
int y = (int) (origin.y - this.radius);
g.setColor(this.color);
g.fillOval(x, y, diameter, diameter);
}
}
ColorUtils.java
import java.awt.Color;
import java.util.Random;
public class ColorUtils {
private static final Random RAND;
static {
RAND = new Random(System.currentTimeMillis());
}
public static Color randHue(float saturation, float brightness) {
return Color.getHSBColor(RAND.nextFloat(), saturation, brightness);
}
}
Extension
You can easily add a class such as a Triangle just by implementing the Shape interface.
DrawPanel#mouseClicked
#Override
public void mouseClicked(MouseEvent e) {
long time = System.currentTimeMillis();
boolean isEven = time % 2 == 0;
if (isEven) {
shapes.add(new Circle(e.getX(), e.getY(), radius, ColorUtils.randHue(sat, bri)));
} else {
shapes.add(new Triangle(e.getX(), e.getY(), radius * 2, ColorUtils.randHue(sat, bri)));
}
repaint();
}
Triangle.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.geom.Point2D;
public class Triangle implements Shape {
private Point origin;
private float side;
private Color color;
private Polygon poly;
public Triangle(int x, int y, float side, Color color) {
this(new Point(x, y), side, color);
}
public Triangle(Point origin, float side, Color color) {
this.origin = origin;
this.side = side;
this.color = color;
recalculate();
}
protected void recalculate() {
this.poly = createPolygon((float) origin.getX(), (float) origin.getY(), side, false);
}
protected Polygon createPolygon(float x, float y, float side, boolean invert) {
float xOff = side / 2f;
float yOff = (float) (xOff * Math.sqrt(3));
float r1 = 1f / 3f;
float r2 = 2f / 3f;
if (invert) {
yOff *= -1;
}
return createPolygon(new Point2D.Float[] {
new Point2D.Float(x, y - (yOff * r2)), // Top
new Point2D.Float(x - xOff, y + (yOff * r1)), // Left
new Point2D.Float(x + xOff, y + (yOff * r1)) // Right
});
}
protected Polygon createPolygon(Point2D.Float[] points) {
int nPoints = points.length + 1;
int xCoords[] = new int[nPoints];
int yCoords[] = new int[nPoints];
for (int i = 0; i < nPoints; i++) {
xCoords[i] = (int) points[i % points.length].x;
yCoords[i] = (int) points[i % points.length].y;
}
return new Polygon(xCoords, yCoords, nPoints);
}
#Override
public Point getOrigin() {
return origin;
}
#Override
public void setOrigin(Point origin) {
this.origin = origin;
recalculate();
}
public float getSide() {
return side;
}
public void setSide(float side) {
this.side = side;
recalculate();
}
#Override
public Color getColor() {
return color;
}
#Override
public void setColor(Color color) {
this.color = color;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(this.color);
g.fillPolygon(poly);
}
}
You should have some initial state, so you know not to draw when it is set.
This can be done with an easy boolean variable, that you set to true when the user has pressed on the screen.
public class DrawPanel extends JPanel implements MouseListener {
private static final long serialVersionUID = 1L;
int x, y;
boolean mustDraw = false;
public DrawPanel() {
setBackground(Color.WHITE);
addMouseListener(this);
}
public void paintComponent(Graphics g) {
if(!mustDraw) return;
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.fillOval(x, y, 20, 20);
}
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
mustDraw = true;
repaint();
}
}
I am trying to create a program that uses a JComboBox containing specific shapes (Circle, Square, Oval, Rectangle). After the user clicks on a specified shape, the Panel will display 20 of that shape in random dimensions and locations.
I am having trouble on how to make the shapes have random dimensions and locations. Here is my code so far. Any advice or sources to look at would be appreciated.
Thank you.
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.awt.event.*;
public class HW1b extends JFrame
{
public HW1b()
{
super("Shapes");
final ComboPanel comboPanel = new ComboPanel();
String[] shapeItems = {"Circle", "Square", "Oval", "Rectangle"};
JComboBox shapeBox = new JComboBox<String>(shapeItems);
shapeBox.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent ie)
{
if (ie.getStateChange() == ItemEvent.SELECTED)
{
String item = (String)ie.getItem();
if(shapeBox.getSelectedItem().equals("Circle"))
comboPanel.makeCircles();
if(shapeBox.getSelectedItem().equals("Square"))
comboPanel.makeSquares();
if(shapeBox.getSelectedItem().equals("Oval"))
comboPanel.makeOvals();
if(shapeBox.getSelectedItem().equals("Rectangle"))
comboPanel.makeRectangles();
}
}
});
JPanel southPanel = new JPanel();
southPanel.add(shapeBox);
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().add(comboPanel, "Center");
getContentPane().add(southPanel, "South");
setSize( 400, 400 );
setLocation( 200, 200 );
setVisible( true );
}
private class ComboPanel extends JPanel
{
int w, h;
Random rand;
static final int OVAL = 0;
static final int RECTANGLE = 1;
int shapeType = -1;
public ComboPanel()
{
rand = new Random();
setBackground(Color.white);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int width = getWidth();
int height = getHeight();
int x, y;
Shape s = null;
for (int i = 0; i < 20; i++)
{
x = rand.nextInt(width - w);
y = rand.nextInt(width - h);
switch(shapeType)
{
case OVAL: s = new Ellipse2D.Double(x,y,w,h);
break;
case RECTANGLE: s = new Rectangle2D.Double(x,y,w,h);
break;
}
if (shapeType > -1)
g2d.draw(s);
}
}
public void makeCircles()
{
shapeType = OVAL;
w = 75;
h = 75;
repaint();
}
public void makeSquares()
{
shapeType = RECTANGLE;
w = 50;
h = 50;
repaint();
}
public void makeOvals()
{
shapeType = OVAL;
w = 80;
h = 60;
repaint();
}
public void makeRectangles()
{
shapeType = RECTANGLE;
w = 80;
h = 40;
repaint();
}
}
public static void main(String[] args)
{
new HW1b();
}
}
You're hard-coding w and h in your code, and so there's no way for this to vary among your shapes. Instead of doing this, use your Random variable, rand, to select random w and h values that are within some desired range. Myself, I wouldn't create my shapes within the paintComponent method since painting is not fully under my control and can occur when I don't want it to. For instance, in your code, your shapes will vary tremendously if the GUI is resized. Instead I'd create a collection such as an ArrayList<Shape> and fill it with created Shape objects (i.e., Ellipse2D for my circles) when desired, and then iterate through that collection within your paintComponent method, drawing your shapes.
for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class SomeShapes extends JPanel {
private ShapePanel shapePanel = new ShapePanel();
private JComboBox<MyShape> myShapeCombo = new JComboBox<>(MyShape.values());
public SomeShapes() {
myShapeCombo.setSelectedIndex(-1);
myShapeCombo.addItemListener(new ComboListener());
JPanel bottomPanel = new JPanel();
bottomPanel.add(myShapeCombo);
setLayout(new BorderLayout());
add(shapePanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
private class ComboListener implements ItemListener {
#Override
public void itemStateChanged(ItemEvent e) {
MyShape myShape = (MyShape) e.getItem();
shapePanel.drawShapes(myShape);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SomeShapes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SomeShapes());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum MyShape {
OVAL("Oval"), RECTANGLE("Rectangle"), SQUARE("Square"), CIRCLE("Circle");
private String name;
private MyShape(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return getName();
}
}
class ShapePanel extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Color SHAPE_COLOR = Color.BLUE;
private static final int SHAPE_COUNT = 20;
private static int MIN = 5;
private static int MAX = 200;
private List<Shape> shapeList = new ArrayList<>();
private Random random = new Random();
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void drawShapes(MyShape myShape) {
shapeList.clear(); // empty the shapeList
switch (myShape) {
case OVAL:
drawOval();
break;
case RECTANGLE:
drawRectangle();
break;
// etc...
default:
break;
}
repaint();
}
private void drawOval() {
// for loop to do this times SHAPE_COUNT(20) times.
for (int i = 0; i < SHAPE_COUNT; i++) {
// first create random width and height
int w = random.nextInt(MAX - MIN) + MIN;
int h = random.nextInt(MAX - MIN) + MIN;
// then random location, but taking care so that it
// fully fits into our JPanel
int x = random.nextInt(getWidth() - w);
int y = random.nextInt(getHeight() - h);
// then create new Shape and place in our shapeList.
shapeList.add(new Ellipse2D.Double(x, y, w, h));
}
}
private void drawRectangle() {
// .... etc
}
//.. .. etc
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// set rendering hints for smooth ovals
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(SHAPE_COLOR);
// iterate through the shapeList ArrayList
for (Shape shape : shapeList) {
g2d.draw(shape); // and draw each Shape it holds
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to create an app that moves a shape left and right depending on the button pushed. I have an int shapesCond and int colorsCond that changes value depending on which option is selected from my JComboBox.
If I only change the value for shapesCond in the "Rectangle" option of the JComboBox, and not in the "Circle" option, a rectangle is printed. But if I change the shapesCond values in both options or change the colorsCond values, my paintComponent(Graphics g) method won't print any shapes.
public class DrawShapes extends JFrame {
public static final int CANVAS_WIDTH = 500;
public static final int CANVAS_HEIGHT = 300;
public static final Color CANVAS_BACKGROUND = Color.YELLOW;
private int x1 = CANVAS_WIDTH / 4;
private int y1 = CANVAS_HEIGHT / 4;
private int rectWidth = CANVAS_WIDTH / 2;
private int rectHeight = CANVAS_HEIGHT / 2;
private int x2 = CANVAS_WIDTH * (1/3);
private int y2 = CANVAS_HEIGHT * (2/5);
private int circWidth = CANVAS_WIDTH * (1/5);
private int circHeight = CANVAS_HEIGHT / 3;
private Color blue = new Color(0, 0, 225);
private int shapesCond = 0;
private int colorsCond = 0;
private CanvasDrawArea canvas;
public DrawShapes() {
JPanel btnPanel = new JPanel(new FlowLayout());
String[] shapeName = {"Rectangle", "Circle"};
JComboBox shapes = new JComboBox(shapeName);
shapes.setSelectedIndex(1);
btnPanel.add(shapes);
shapes.addActionListener(new ActionListener(){ //shapes combobox
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox)e.getSource(); //copies shapes combo box
String msg = (String)cb.getSelectedItem();
switch(msg){
case "Rectangle":
shapesCond = 1;
break;
case "Circle":
shapesCond = 2;
}//switch end
}
}); //action listener end
String[] colorName = {"Red", "Blue", "Green"};
JComboBox colors = new JComboBox(colorName); //colors combobox
colors.setSelectedIndex(1);
btnPanel.add(colors);
shapes.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
JComboBox cb = (JComboBox)e.getSource(); //copies shapes combo box
String msg = (String)cb.getSelectedItem();
switch(msg){
case "Red" :
colorsCond = 1;
break;
case "Blue" :
colorsCond = 2;
break;
case "Green" :
colorsCond = 3;
break;
}
}
});
canvas = new CanvasDrawArea();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(btnPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Drawing Shapes: Moving Shapes");
pack();
setVisible(true);
requestFocus();
}//DrawShapes constructor end
class CanvasDrawArea extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (shapesCond == 1 && colorsCond == 1) { //red rectangle
g.setColor(Color.RED);
g.fillRect(x1, y1, rectWidth, rectHeight);
repaint();
}
if (shapesCond == 1 && colorsCond == 2) { //blue rectangle
g.setColor(Color.BLUE);
g.fillRect(x1, y1, rectWidth, rectHeight);
repaint();
}
if (shapesCond == 1 && colorsCond == 3) { //green rectangle
g.setColor(Color.GREEN);
g.fillRect(x1, y1, rectWidth, rectHeight);
repaint();
}
if (shapesCond == 2 && colorsCond == 1) { // red circle
g.setColor(Color.RED);
g.fillOval(x2, y2, circWidth, circHeight);
repaint();
}
if (shapesCond == 2 && colorsCond == 2) { //blue circle
g.setColor(Color.BLUE);
g.fillOval(x2, y2, circWidth, circHeight);
repaint();
}
if (shapesCond == 2 && colorsCond == 3) { //green circle
g.setColor(Color.GREEN);
g.fillOval(x2, y2, circWidth, circHeight);
repaint();
}
}//paintComponent method end
}//CanvasDrawArea class end
}//DrawShapes class end
And then here's my main method. It's in a separate class called Main.
import javax.swing.SwingUtilities;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DrawShapes();
}
});
}
}
circWidth is 0...1 / 5 is a integer division, meaning that the trailing decimals are trimmed off, meaing it's equal to 0, so 0 * anything is 0...
You could use something like (int)(CANVAS_WIDTH * (1 / 5f)) instead...
You're adding the ActionListener for the colors combobox to the shapes combobox...
JComboBox colors = new JComboBox(colorName); //colors combobox
colors.setSelectedIndex(1);
btnPanel.add(colors);
shapes.addActionListener(new ActionListener(){
It would be better to place shapes.setSelectedIndex(1); and colors.setSelectedIndex(1); after the registration of the ActionListeners, this will allow them to trigger the ActionListeners and prime the initial values...
The if statements in the paintComponent method could be changed to something more like...
switch (colorsCond) {
case 1:
g.setColor(Color.RED);
break;
case 2:
g.setColor(Color.BLUE);
break;
case 3:
g.setColor(Color.GREEN);
break;
}
switch (shapesCond) {
case 1:
g.fillRect(x1, y1, rectWidth, rectHeight);
break;
case 2:
g.fillOval(x2, y2, circWidth, circHeight);
break;
}
Which would reduce the code clutter and repeation and make it easier what is suppose to be happening...
At the end of your actionPerformed methods, you need to call repaint
And just for comparison...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawShapes {
public static void main(String[] args) {
new DrawShapes();
}
public DrawShapes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawingPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawingPane extends JPanel {
private JComboBox cbShape;
private JComboBox cbColor;
private CanvasPane canvasPane;
public DrawingPane() {
setLayout(new BorderLayout());
canvasPane = new CanvasPane();
JPanel controls = new JPanel();
cbShape = new JComboBox(new String[]{"Rectangle", "Circle"});
cbColor = new JComboBox(new ColorEntry[]{
new ColorEntry("Red", Color.RED),
new ColorEntry("Green", Color.GREEN),
new ColorEntry("Blue", Color.BLUE),
new ColorEntry("Magenta", Color.MAGENTA)});
cbColor.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); //To change body of generated methods, choose Tools | Templates.
if (value instanceof ColorEntry) {
Color color = ((ColorEntry)value).getColor();
setBackground(color);
setOpaque(true);
}
return this;
}
});
JButton apply = new JButton("Apply");
apply.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CustomShape shape = null;
ColorEntry entry = (ColorEntry) cbColor.getSelectedItem();
Color color = entry == null ? null : entry.getColor();
if (color != null) {
int width = canvasPane.getWidth() / 2;
int height = canvasPane.getHeight() / 2;
switch (cbShape.getSelectedIndex()) {
case 0: {
int x = (canvasPane.getWidth() - width) / 2;
int y = (canvasPane.getHeight() - height) / 2;
shape = new CustomRectangle(x, y, width, height, color);
}
break;
case 1: {
int diameter = Math.min(width, height);
int x = (canvasPane.getWidth() - diameter) / 2;
int y = (canvasPane.getHeight() - diameter) / 2;
shape = new CustomCircle(x, y, diameter, color);
}
break;
}
}
canvasPane.setShape(shape);
}
});
controls.add(cbShape);
controls.add(cbColor);
controls.add(apply);
add(canvasPane);
add(controls, BorderLayout.SOUTH);
}
}
public class ColorEntry {
private String name;
private Color color;
public ColorEntry(String name, Color color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public Color getColor() {
return color;
}
#Override
public String toString() {
return getName();
}
}
public class CanvasPane extends JPanel {
private CustomShape shape;
public CanvasPane() {
}
public void setShape(CustomShape shape) {
this.shape = shape;
repaint();
}
public CustomShape getShape() {
return shape;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (shape != null) {
Graphics2D g2d = (Graphics2D) g;
shape.paint(g2d);
}
}
}
public interface CustomShape {
public Rectangle getBounds();
public Color getColor();
public void paint(Graphics2D g2d);
}
public abstract class AbstractCustomShape implements CustomShape {
private Rectangle bounds;
private Color color;
#Override
public Rectangle getBounds() {
return bounds;
}
#Override
public Color getColor() {
return color;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public void setColor(Color color) {
this.color = color;
}
}
public class CustomRectangle extends AbstractCustomShape {
public CustomRectangle(int x, int y, int width, int height, Color color) {
setBounds(new Rectangle(x, y, width, height));
setColor(color);
}
#Override
public void paint(Graphics2D g2d) {
g2d.setColor(getColor());
g2d.fill(getBounds());
}
}
public class CustomCircle extends AbstractCustomShape {
public CustomCircle(int x, int y, int diameter, Color color) {
setBounds(new Rectangle(x, y, diameter, diameter));
setColor(color);
}
#Override
public void paint(Graphics2D g2d) {
g2d.setColor(getColor());
Rectangle bounds = getBounds();
Ellipse2D circle = new Ellipse2D.Double(bounds.x, bounds.y, bounds.width, bounds.height);
g2d.fill(circle);
}
}
}