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();
}
}
Related
I have a problem with repaint() method in my Java code. I want to call it in another class but I can't, something doesn't work at all. I've searched on forums, but nothing was able to help me out.
My Main class:
public class Main {
public static Main main;
public static JFrame f;
public Main(){
}
public static void main(String[] args) {
main = new Main();
f = new JFrame();
Ball b = new Ball();
f.getContentPane().setBackground(Color.GRAY);
f.add(b);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setTitle("Test");
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addMouseMotionListener(b);
f.addKeyListener(new Key());
}
}
Ball class where I created 2DGraphics for moving shapes:
public class Ball extends JLabel implements MouseMotionListener{
public Ball(){
}
public static double x = 10;
public static double y = 10;
public static double width = 40;
public static double height = 40;
String nick;
boolean isEllipse = true;
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
if(isEllipse){
Ellipse2D e2d = new Ellipse2D.Double(x, y, width, height);
g2d.setColor(Color.RED);
g2d.fill(e2d);
}
else{
Rectangle2D r2d = new Rectangle2D.Double(x, y, width, height);
g2d.setColor(Color.GREEN);
g2d.fill(r2d);
}
}
#Override
public void mouseDragged(MouseEvent e) {
isEllipse = false;
x = e.getX() - 30;
y = e.getY() - 40;
this.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
x = e.getX() - 30;
y = e.getY() - 40;
isEllipse = true;
this.repaint();
}
}
And Key class where I put KeyListener for move the shapes by key pressing:
public class Key extends Ball implements KeyListener {
public Key() {
}
#SuppressWarnings("static-access")
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
super.x += 10;
super.repaint();
System.out.println("x: " + super.x);
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
But something is wrong with this code: super method doesn't work for Key class. Everything in Ball class is working well. Where is the problem?
Super works fine, but your interpretation of what it does is wrong. Your problem is that you're trying to use inheritance to solve a problem that isn't solved with inheritance. You need to call repaint() on the actual visualized and used Ball instance, not on an instance of some completely different class, Key, that inappropriately extends from Ball. First off, make Key not extend Ball, pass in a true Ball reference into Key and the solution will fall from that.
Perhaps do something like this:
f.addKeyListener(new Key(b));
and
public class Key implements KeyListener {
private Ball ball;
public Key(Ball ball) {
this.ball = ball;
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
b.incrX(10); // give Ball a public method for this
b.repaint();
// System.out.println("x: " + super.x);
}
}
// .... etc...
Note, myself, I'd use Key Bindings for this, not a KeyListener, since then I wouldn't have to futz with keyboard focus.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.*;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class MoveBall {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private static void createAndShowGui() {
BallPanel ballPanel = new BallPanel(PREF_W, PREF_H);
MyMouse myMouse = new MyMouse(ballPanel);
ballPanel.addMouseListener(myMouse);
ballPanel.addMouseMotionListener(myMouse);
new CreateKeyBindings(ballPanel);
JFrame frame = new JFrame("MoveBall");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(ballPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
#SuppressWarnings("serial")
class BallPanel extends JPanel {
private static final Color ELLIPSE_COLOR = Color.RED;
private static final Color SQUARE_COLOR = Color.GREEN;
private static final int BALL_WIDTH = 40;
private int prefW;
private int prefH;
private boolean isEllipse = true;
private int ballX;
private int ballY;
public BallPanel(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
}
public boolean isEllipse() {
return isEllipse;
}
public void setEllipse(boolean isEllipse) {
this.isEllipse = isEllipse;
}
public int getBallX() {
return ballX;
}
public void setBallX(int ballX) {
this.ballX = ballX;
}
public void setXY(int x, int y) {
ballX = x;
ballY = y;
repaint();
}
public void setXYCenter(int x, int y) {
ballX = x - BALL_WIDTH / 2;
ballY = y - BALL_WIDTH / 2;
repaint();
}
public void setXYCenter(Point p) {
setXYCenter(p.x, p.y);
}
public int getBallY() {
return ballY;
}
public void setBallY(int ballY) {
this.ballY = ballY;
}
public void incrementBallX(int x) {
ballX += x;
repaint();
}
public void incrementBallY(int y) {
ballY += y;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (isEllipse) {
g2.setColor(ELLIPSE_COLOR);
g2.fillOval(ballX, ballY, BALL_WIDTH, BALL_WIDTH);
} else {
g2.setColor(SQUARE_COLOR);
g2.fillOval(ballX, ballY, BALL_WIDTH, BALL_WIDTH);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
}
class MyMouse extends MouseAdapter {
private BallPanel ballPanel;
public MyMouse(BallPanel ballPanel) {
this.ballPanel = ballPanel;
}
#Override
public void mousePressed(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e) {
ballPanel.setXYCenter(e.getPoint());
}
}
enum Direction {
UP(KeyEvent.VK_UP), DOWN(KeyEvent.VK_DOWN), LEFT(KeyEvent.VK_LEFT), RIGHT(KeyEvent.VK_RIGHT);
private int key;
private Direction(int key) {
this.key = key;
}
public int getKey() {
return key;
}
}
// Actions for the key binding
#SuppressWarnings("serial")
class MyKeyAction extends AbstractAction {
private static final int STEP_DISTANCE = 5;
private BallPanel ballPanel;
private Direction direction;
public MyKeyAction(BallPanel ballPanel, Direction direction) {
this.ballPanel = ballPanel;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
switch (direction) {
case UP:
ballPanel.incrementBallY(-STEP_DISTANCE);
break;
case DOWN:
ballPanel.incrementBallY(STEP_DISTANCE);
break;
case LEFT:
ballPanel.incrementBallX(-STEP_DISTANCE);
break;
case RIGHT:
ballPanel.incrementBallX(STEP_DISTANCE);
break;
default:
break;
}
}
}
class CreateKeyBindings {
private BallPanel ballPanel;
public CreateKeyBindings(BallPanel ballPanel) {
this.ballPanel = ballPanel;
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = ballPanel.getInputMap(condition);
ActionMap actionMap = ballPanel.getActionMap();
for (Direction direction : Direction.values()) {
KeyStroke keyStroke = KeyStroke.getKeyStroke(direction.getKey(), 0);
String keyString = keyStroke.toString();
inputMap.put(keyStroke, keyString);
actionMap.put(keyString, new MyKeyAction(ballPanel, direction));
}
}
}
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 making a gui program with the mouseListener and mouseMotionListener. I have the following Line class
public class Line {
private int x1, x2, y1, y2;
private Color color;
public Line(int x1, int x2, int y1, int y2, Color color)
{
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.color = color;
}
public void draw(Graphics page)
{
page.drawLine(x1, y1, x2, y2);
page.setColor(color);
}
}
here is my mouseReleased where i get the final points of the desired line.
public void mouseReleased (MouseEvent event)
{ // ending points
moving = false;
Point p2 = event.getPoint();
x2 = p2.x;
y2 = p2.y;
line = new Line(x1,x2,y1,y2,currentColor);
lineList.add(line);
canvas.paintComponent(??????????);
Here is the canvas method that should draw all of these lines in the array list "lineList". to the canvas
private class CanvasPanel extends JPanel
{
//this method draws all shapes specified by a user
public void paintComponent(Graphics page)
{
super.paintComponent(page);
setBackground(Color.WHITE);
for(int i = 0; i <lineList.size()-1;i++)
{
line.draw(page);
}
However I do not know how to pass the graphics object to the canvas class in order to actually draw my lines on the JPanel. Assuming i have all other info correct(initial line points, JPanel set correctly, and buttons set up) how do i pass these to actually make it draw the lines to the canvas. Thank you!
No, you don't want to pass a Graphics object anywhere, and in fact you don't paint from within the MouseListener or MouseMotionListener. Instead you change fields from within those classes, call repaint() and then use the field results in your paintComponent method.
In fact in your code, if CanvasPanel has access to the lineList, all you need to do is call repaint() on it after adding a new line into the lineList collection. That's it.
Also, don't set background within paintComponent but rather within the constructor. Also you need to swap your method calls in the Line's draw method. You need to set the color before drawing the line.
e.g.,
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class Drawing extends JPanel {
public static final Color BG = Color.WHITE;
public static final Color LINE_COLOR = Color.RED;
public static final Color CURRENT_LINE_COLOR = Color.LIGHT_GRAY;
public static final int PREF_W = 800;
public static final int PREF_H = PREF_W;
private List<Line> lineList = new ArrayList<>();
private Line currentLine = null;
private CanvasPanel canvasPanel = new CanvasPanel();
public Drawing() {
MyMouse myMouse = new MyMouse();
canvasPanel.addMouseListener(myMouse);
canvasPanel.addMouseMotionListener(myMouse);
setLayout(new BorderLayout());
add(canvasPanel);
}
private class CanvasPanel extends JPanel {
public CanvasPanel() {
setBackground(BG);
}
public void paintComponent(Graphics page) {
super.paintComponent(page);
// setBackground(Color.WHITE); // !! no, not here
for (Line line : lineList) {
line.draw(page);
}
if (currentLine != null) {
currentLine.draw(page);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}
private class MyMouse extends MouseAdapter {
private int x1;
private int y1;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
x1 = e.getX();
y1 = e.getY();
currentLine = null;
canvasPanel.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
Line line = createLine(e, LINE_COLOR);
lineList.add(line);
currentLine = null;
canvasPanel.repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, CURRENT_LINE_COLOR);
repaint();
}
private Line createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new Line(x1, x2, y1, y2, currentColor);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Drawing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Drawing());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Line {
private int x1, x2, y1, y2;
private Color color;
public Line(int x1, int x2, int y1, int y2, Color color) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.color = color;
}
public void draw(Graphics page) {
// swap these calls!
page.setColor(color); //!! This first!
page.drawLine(x1, y1, x2, y2); // **Then** this
// !! page.setColor(color);
}
}
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.
I am trying to create a program that record mouse clicks, draw lines between those points and after some calculations display some circles through a button call. My problem is that I can display the lines or the circles, but not both.
I know there is something overlapping something else, but I am very new to Java and I don't know how to fix it. Here is the code:
package fempack;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.lang.Math;
public class MainFem extends JPanel {
final DrawPoints Npoints = new DrawPoints();
final DrawLines Nline = new DrawLines();
private static final long serialVersionUID = 1L;
private MouseHandler mouseHandler = new MouseHandler();
private Point p1 = new Point(100, 100);
public int Xpoint[][] = new int[500][30];
public int Ypoint[][] = new int[500][30];
private double Xmpoint[][] = new double[500][1000]; // [i γραμμή][συντεταγμένη Χ]
private double Ympoint[][] = new double[500][1000];
private double Vec[][][] = new double[500][2][500]; // [i γραμμή][0,1][0α 1β]
private double dist[] = new double[10000];
private boolean drawing;
private int c1;
private int c2;
public MainFem() {
this.addMouseListener(mouseHandler);
this.addMouseMotionListener(mouseHandler);
}
// -------------- Draw by clicking -----------------------
private class MouseHandler extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if(SwingUtilities.isRightMouseButton(e)){
drawing=false;
c2++;
}
if(SwingUtilities.isLeftMouseButton(e)){
p1 = e.getPoint();
Xpoint[c1][c2] = p1.x;
Ypoint[c1][c2] = p1.y;
if (c1 > 3) {
for (int j = 0; j<c2+1; j++){
for (int i = 0; i<c1; i++){
if ((Math.abs(Xpoint[i][j]-Xpoint[c1][c2]) < 10) && (Math.abs(Ypoint[i][j]-Ypoint[c1][c2]) < 10)) {
Xpoint[c1][c2] = Xpoint[i][j];
Ypoint[c1][c2] = Ypoint[i][j];
System.out.println(Xpoint[i][j]);
}
}
}
}
if (drawing == true){
Nline.addLine(Xpoint[c1][c2], Ypoint[c1][c2], Xpoint[c1-1][c2], Ypoint[c1-1][c2]);
}
c1++;
drawing = true;
}
}
}
// ---------------- Create Mesh Points --------------------------
public void createmesh() {
int mdi = 0;
for (int j = 0; j<=c2; j++){
for (int i = 0; i<c1-1; i++){
// Υπολογισμός a και b συνιστωσών της εξίσωσης της γραμμής
Vec[i][0][mdi] = (Ypoint[i+1][j] - Ypoint[i][j])/(Xpoint[i+1][j] - Xpoint[i][j]);
Vec[i][1][mdi] = Ypoint[i][j] - Xpoint[i][j]*Vec[i][1][mdi];
// Υπολογισμός μέτρου διανύσματος
dist[mdi] = Math.sqrt(Math.pow(Xpoint[i][j] - Xpoint[i+1][j], 2) + Math.pow(Ypoint[i][j] - Ypoint[i+1][j], 2) );
// Υπολογισμός ενδιάμεσον σημείων
int nkom = 3;
double xa = Xpoint[i][j];
double ya = Ypoint[i][j];
for (int ii = 0; ii <nkom; ii++) {
double a = Vec[i][0][mdi];
double b = Vec[i][1][mdi];
Xmpoint[i][ii] = (-((2*a)*(b - ya) - 2*xa) + Math.sqrt(Math.abs(Math.pow(((2*a)*(b - ya) - 2*xa), 2) - 4*(1 + a*a)*(xa*xa + Math.pow((b - ya),2) - Math.pow(dist[mdi]/nkom,2)))))/(2 + 2*a*a);
Ympoint[i][ii] = a*Xmpoint[i][ii] + b;
double xm11 = Xmpoint[i][ii];
double ym11 = Ympoint[i][ii];
int xm1 = (int) xm11;
int ym1 = (int) ym11;
Npoints.addPoint(xm1, ym1);
System.out.println("i:" + ym11 + "...ii:" + ym1 );
xa = Xmpoint[i][ii];
ya = Ympoint[i][ii];
}
mdi++;
}
}
}
//------------------------- Display ---------------------------
private void display() {
JFrame f = new JFrame("LinePanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setPreferredSize(new Dimension(500, 600));
f.setLocationRelativeTo(null);
f.add(Npoints);
f.add(Nline);
JPanel buttonsPanel = new JPanel();
//-----------------Complete---------------
JButton dcomp = new JButton("Complete");
buttonsPanel.add(dcomp);
dcomp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
createmesh();
}
});
//------------------Clean-------------------
JButton clearButton = new JButton("Clear");
buttonsPanel.setBorder(BorderFactory.createLineBorder(Color.black));
buttonsPanel.setPreferredSize(new Dimension(500, 100));
f.add(buttonsPanel, BorderLayout.SOUTH);
buttonsPanel.add(clearButton);
clearButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Nline.clearLines();
}
});
f.pack();
f.setVisible(true);
f.add(this);
}
//---------------------------------------------------------
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MainFem().display();
}
});
}
}
Class to draw lines:
package fempack;
import java.awt.Graphics;
import java.util.LinkedList;
import javax.swing.JPanel;
public class DrawLines extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public DrawLines() {
}
private static class Line{
final int x1;
final int y1;
final int x2;
final int y2;
public Line(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
private final LinkedList<Line> lines = new LinkedList<Line>();
public void addLine(int x1, int x2, int x3, int x4) {
lines.add(new Line(x1,x2,x3,x4));
repaint();
}
public void clearLines() {
lines.clear();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Line line : lines) {
// System.out.println(line);
g.drawLine(line.x1, line.y1, line.x2, line.y2);
}
}
}
And class to draw Circles:
package fempack;
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.LinkedList;
public class DrawPoints extends JPanel {
private static final long serialVersionUID = 1L;
public DrawPoints() {
}
private static class Point {
final int x;
final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
private final LinkedList<Point> points = new LinkedList<Point>();
public void addPoint(int x, int y) {
points.add(new Point(x,y));
// System.out.println(x);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point : points) {
// System.out.println(point);
g.drawOval(point.x, point.y, 5, 5);
}
}
}
Here is my solution to draw the points added in the createmesh(). I did not modify any handling of the points you got from the mouse position. I just tried to refactor and clean up your code.
Now DrawLine and DrawPoint are no more JPanel's they just hold the data you give them and draw to the Graphics-Object you pass to them in public void draw(Graphics g) method, which is called on paint in the DrawPanel-Class. DrawPanel inherits from JPanel and overrides void PaintComponent(Graphics g); to realize this (Thanks to MadProgrammer ;). Also DrawPanel handels the MouseEvents to put the mouse-positions into DrawLines- and DrawPoints-objects.
MainWindow inherits from JFrame and is the MainWindow. It creates all GUI-elements and calls the DrawPanel if necessary.
MainWindow:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainWindow extends JFrame {
private static final long serialVersionUID = 6755417048009930291L;
// begin gui components
JButton clearButton = null;
JButton dcomp = null;
JPanel buttonsPanel = null;
DrawPanel drawPanel = null;
// end gui components
public MainWindow(){
// Add ButtonPanel
add(getDrawPanel(), BorderLayout.CENTER);
add(getButtonPanel(), BorderLayout.SOUTH);
// Add Buttons
getButtonPanel().add(getDcomp());
getButtonPanel().add(getClearButton());
addMouseListener(getDrawPanel());
}
// begin getters and setters for gui components
private DrawPanel getDrawPanel(){
if(drawPanel == null){
drawPanel = new DrawPanel();
drawPanel.setVisible(true);
}
return drawPanel;
}
private JPanel getButtonPanel() {
if(buttonsPanel == null){
buttonsPanel = new JPanel();
buttonsPanel.setBorder(BorderFactory.createLineBorder(Color.black));
buttonsPanel.setPreferredSize(new Dimension(500, 100));
}
return buttonsPanel;
}
private JButton getClearButton() {
if(clearButton == null){
clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getDrawPanel().clearLines();
}
});
}
return clearButton;
}
private JButton getDcomp() {
if(dcomp == null){
dcomp = new JButton("Complete");
dcomp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
getDrawPanel().createmesh();
getDrawPanel().repaint();
}
});
}
return dcomp;
}
// end begin getters and setters for gui components
//as always program entry-point
public static void main(String[] args) {
MainWindow wnd = new MainWindow();
wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wnd.setPreferredSize(new Dimension(500, 600));
wnd.setLocationRelativeTo(null);
wnd.pack();
wnd.setVisible(true);
}
}
DrawPanel:
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class DrawPanel extends JPanel implements MouseListener {
private static final long serialVersionUID = -7726303639184194659L;
// begin members
private DrawLines dlines;
private DrawPoints dpoints;
// dont know what these members do
private Point p1 = new Point(100, 100);
public int Xpoint[][] = new int[500][30];
public int Ypoint[][] = new int[500][30];
private double Xmpoint[][] = new double[500][1000]; // [i
// γραμμή][συντεταγμένη
// Χ]
private double Ympoint[][] = new double[500][1000];
private double Vec[][][] = new double[500][2][500]; // [i γραμμή][0,1][0α
// 1β]
private double dist[] = new double[10000];
private boolean drawing;
private int c1;
private int c2;
// end members
public DrawPanel() {
dlines = new DrawLines();
dpoints = new DrawPoints();
addMouseListener(this);
}
// begin class logic
public void clearLines(){
dlines.clearLines();
repaint();
}
// dont know what this does
public void createmesh() {
int mdi = 0;
for (int j = 0; j <= c2; j++) {
for (int i = 0; i < c1 - 1; i++) {
// Υπολογισμός a και b συνιστωσών της εξίσωσης της γραμμής
Vec[i][0][mdi] = (Ypoint[i + 1][j] - Ypoint[i][j])
/ (Xpoint[i + 1][j] - Xpoint[i][j]);
Vec[i][1][mdi] = Ypoint[i][j] - Xpoint[i][j] * Vec[i][1][mdi];
// Υπολογισμός μέτρου διανύσματος
dist[mdi] = Math.sqrt(Math.pow(Xpoint[i][j] - Xpoint[i + 1][j],
2) + Math.pow(Ypoint[i][j] - Ypoint[i + 1][j], 2));
// Υπολογισμός ενδιάμεσον σημείων
int nkom = 3;
double xa = Xpoint[i][j];
double ya = Ypoint[i][j];
for (int ii = 0; ii < nkom; ii++) {
double a = Vec[i][0][mdi];
double b = Vec[i][1][mdi];
Xmpoint[i][ii] = (-((2 * a) * (b - ya) - 2 * xa) + Math
.sqrt(Math.abs(Math.pow(
((2 * a) * (b - ya) - 2 * xa), 2)
- 4
* (1 + a * a)
* (xa * xa + Math.pow((b - ya), 2) - Math
.pow(dist[mdi] / nkom, 2)))))
/ (2 + 2 * a * a);
Ympoint[i][ii] = a * Xmpoint[i][ii] + b;
double xm11 = Xmpoint[i][ii];
double ym11 = Ympoint[i][ii];
int xm1 = (int) xm11;
int ym1 = (int) ym11;
dpoints.addPoint(xm1, ym1);
System.out.println("i:" + ym11 + "...ii:" + ym1);
xa = Xmpoint[i][ii];
ya = Ympoint[i][ii];
}
mdi++;
}
}
}
// end class logic
// begin MouseListener implementation
#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) {
if (SwingUtilities.isRightMouseButton(e)) {
drawing = false;
c2++;
}
if (SwingUtilities.isLeftMouseButton(e)) {
p1 = e.getPoint();
Xpoint[c1][c2] = p1.x;
Ypoint[c1][c2] = p1.y;
if (c1 > 3) {
for (int j = 0; j < c2 + 1; j++) {
for (int i = 0; i < c1; i++) {
if ((Math.abs(Xpoint[i][j] - Xpoint[c1][c2]) < 10)
&& (Math.abs(Ypoint[i][j] - Ypoint[c1][c2]) < 10)) {
Xpoint[c1][c2] = Xpoint[i][j];
Ypoint[c1][c2] = Ypoint[i][j];
System.out.println(Xpoint[i][j]);
}
}
}
}
if (drawing == true) {
dlines.addLine(Xpoint[c1][c2], Ypoint[c1][c2],
Xpoint[c1 - 1][c2], Ypoint[c1 - 1][c2]);
}
c1++;
drawing = true;
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
// end MouseListener implementation
// beging PAINTING
#Override
protected void paintComponent(Graphics g) {
System.out.println("paintComponent");
super.paintComponent(g);
dlines.draw(g);
dpoints.draw(g);
}
// end PAINTING
}
DrawPoints:
import java.awt.Graphics;
import java.util.LinkedList;
public class DrawPoints {
public DrawPoints() {
}
private static class Point {
final int x;
final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
private final LinkedList<Point> points = new LinkedList<Point>();
public void addPoint(int x, int y) {
points.add(new Point(x, y));
}
public void draw(Graphics g){
for (Point point : points) {
g.drawOval(point.x, point.y, 5, 5);
}
}
}
DrawLines:
import java.awt.Graphics;
import java.util.LinkedList;
public class DrawLines{
public DrawLines() {
}
private static class Line {
final int x1;
final int y1;
final int x2;
final int y2;
public Line(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
private final LinkedList<Line> lines = new LinkedList<Line>();
public void addLine(int x1, int x2, int x3, int x4) {
lines.add(new Line(x1, x2, x3, x4));
}
public void clearLines() {
lines.clear();
}
public void draw(Graphics g){
for (Line line : lines) {
g.drawLine(line.x1, line.y1, line.x2, line.y2);
}
}
}
I think its a good idea to handle things like this. You want to paint on a Panel or something so pass it to the object which hold your data and let them draw to their common canvas like I did with the void draw(Graphics g) method in DrawPoints- and DrawLines-class.
I hope this will help you.
Fell free to ask if something is unclear.