I am working on a simple panting project that allow the user to select a shape from ComboBox then draw it on the panel. Problem is when user choose any type of shapes and try to draw it on panel no shape appears.
here is my panel class
import java.awt.Color;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
public class Shapes extends JPanel {
private MyLine[] lines = new MyLine[100];
private MyRectangle[] recs;
private MyOval[] ovals;
int ShapeType = 0;
int LC = 0;// conter for number of lines
int RC = 0;// conter for number of rectable
int OC = 0;// conter for number of ovals
int x1;
int y1;
int x2;
int y2;
Shapes() {
this.setBackground(Color.WHITE);
this.setBounds(0, 100, 300, 300);
MouseHandler handler = new MouseHandler();
this.addMouseListener(handler);
this.addMouseMotionListener(handler);
}
public int getShapeType() {
return ShapeType;
}
public void setShapeType(int ShapeType) {
this.ShapeType = ShapeType;
}
private class MouseHandler extends MouseAdapter implements
MouseMotionListener {
#Override
public void mouseClicked(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getX();
repaint();
System.out.println(x1 + " " + y1);
}
#Override
public void mouseReleased(MouseEvent e) {
x2 = e.getX();
y2 = e.getX();
lines[LC] = new MyLine(x1, y1, x2, y2);
LC++;
System.out.println(x2 + " " + y2);
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
x2 = e.getX();
y2 = e.getX();
System.out.println(x2 + " dragged " + y2);
repaint();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
if (ShapeType == 0) {
for (int i = 0; i < LC; i++) {
lines[i].draw(g);
}
}
if (ShapeType == 1) {
for (int i = 0; i < LC; i++) {
lines[i].draw(g);
}
}
if (ShapeType == 1) {
for (int i = 0; i < LC; i++) {
lines[i].draw(g);
}
}
}
}
MyLine Class
package painter;
import java.awt.Graphics;
import java.awt.Color;
public class MyLine extends MyShape {
MyLine(int x1, int y1, int x2, int y2) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
this.c = c;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.RED);
g.drawLine(500, 200, 300, 400);
}
}
Your panel is way too small: it's 300 by 300 pixels, but when you draw the line, you start it at (500,200) which is out of the bounds of your panel:
g.drawLine(500, 200, 300, 400);
Try drawing it closer to the upper-left corner:
g.drawLine(0, 0, 300, 400);
Related
I'm trying to create Circles in JFrame using JComponent. Here's what I'm trying to achieve:
And here's what's happening with my code:
I have no idea what's causing this problem. Here's my code:
CircleViewer.java
import javax.swing.JFrame;
import java.awt.event.*;
public class CircleViewer
{
public static void main(String[] args)
{
final CirclePanel panel = new CirclePanel();
class MousePressListener implements MouseListener, MouseMotionListener
{
public void mouseClicked(MouseEvent event) { }
public void mouseEntered(MouseEvent event) { }
public void mouseExited(MouseEvent event) { }
public void mouseWheelMoved(MouseWheelEvent event) { }
public void mouseMoved(MouseEvent event) { }
public void mousePressed(MouseEvent event)
{
var x = event.getX();
var y = event.getY();
panel.addCircle(x, y);
}
public void mouseDragged(MouseEvent event)
{
var x = event.getX();
var y = event.getY();
panel.moveTo(x, y);
}
public void mouseReleased(MouseEvent event)
{
panel.finalMove();
}
}
MousePressListener listener = new MousePressListener();
panel.addMouseListener(listener);
panel.addMouseMotionListener(listener);
JFrame frame = new JFrame("Circle Shapes");
frame.setSize(FRAME_WIDTH, FRAME_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
}
private static final int FRAME_WIDTH = 700;
private static final int FRAME_HEIGHT = 500;
}
CirclePanel.java
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JComponent;
import java.util.ArrayList;
import java.awt.Color;
import java.lang.Math;
import java.awt.BasicStroke;
import java.awt.Stroke;
public class CirclePanel extends JComponent
{
private int lineX;
private int lineY;
private boolean isDraged;
private ArrayList<Circle> circleList;
private BasicStroke dashLine;
public CirclePanel()
{
this.circleList = new ArrayList<Circle>();
this.isDraged = false;
this.lineX = 0;
this.lineY = 0;
this.dashLine = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{6}, 0);
}
public void addCircle(int x, int y)
{
lineX = x;
lineY = y;
isDraged = true;
circleList.add(new Circle(x, y, 0, Color.RED));
repaint();
}
public void moveTo(int x, int y)
{
var circleTemp = circleList.get(circleList.size() - 1);
isDraged = true;
var tempR = (int)Math.sqrt(Math.pow(x - circleTemp.get(0), 2) + Math.pow(y - circleTemp.get(1), 2));
System.out.println(tempR);
var tempX = circleTemp.get(0) - (tempR / 2);
var tempY = circleTemp.get(1) - (tempR / 2);
circleList.get(circleList.size() - 1).setCords(tempX, tempY, tempR);
lineX = x;
lineY = y;
repaint();
}
public void finalMove()
{
isDraged = false;
circleList.get(circleList.size() - 1).setColor(Color.BLUE);
repaint();
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
Stroke defaultStroke;
defaultStroke = g2.getStroke();
if (!circleList.isEmpty())
{
if (isDraged)
{
g2.setColor(Color.RED);
g2.setStroke(dashLine);
g2.drawLine(circleList.get(circleList.size() - 1).get(0), circleList.get(circleList.size() - 1).get(1), lineX, lineY);
}
for (Circle circle : circleList)
{
g2.setStroke(defaultStroke);
circle.draw(g2);
isDraged = false; //this is prob reduntant
}
}
}
}
And finally, Circle.java
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class Circle
{
private int x;
private int y;
private int radius;
private Color color;
public Circle(int x, int y, int radius, Color color)
{
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
}
public int get(int option)
{
switch (option)
{
case 0:
return this.x;
case 1:
return this.y;
case 2:
return this.radius;
}
return 0;
}
public Color get()
{
return this.color;
}
public void setCords(int x, int y, int r)
{
this.x = x;
this.y = y;
this.radius = r;
}
public void set(int option, int value)
{
switch (option)
{
case 0: //set x
this.x = value;
break;
case 1:
this.y = value;
break;
case 2:
radius = value;
break;
}
}
public void setColor(Color color)
{
this.color = color;
}
public void draw(Graphics2D g2)
{
g2.setColor(color);
g2.draw(new Ellipse2D.Double(x, y, radius, radius));
}
}
Rather than finding the specific problem in you code, I just decided to make a cleaner implementation. Using this circle class
class Circle {
final int x;
final int y;
int radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
}
You can implement CirclePanel like this:
public class CirclePanel extends JPanel {
private static final Stroke DASHED = new BasicStroke(1,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL,
0, new float[]{6}, 0);
public Color oldCircleColor = Color.BLUE;
public Color newCircleColor = Color.RED;
public Color backgroundColor = Color.LIGHT_GRAY;
private final List<Circle> oldCircles = new ArrayList<>();
private Circle newCircle = null;
private int mouseX = 0;
private int mouseY = 0;
private class MouseHelper implements MouseListener, MouseMotionListener {
#Override public void mouseMoved(MouseEvent e) {}
#Override public void mouseClicked(MouseEvent e) {}
#Override public void mousePressed(MouseEvent e) {}
#Override public void mouseEntered(MouseEvent e) {}
#Override public void mouseExited(MouseEvent e) {}
#Override
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
if (newCircle == null) {
newCircle = new Circle(mouseX, mouseY, 0);
} else {
int dX = newCircle.x - mouseX;
int dY = newCircle.y - mouseY;
newCircle.radius = (int) Math.sqrt(dX*dX + dY*dY);
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
if (newCircle != null) {
oldCircles.add(newCircle);
newCircle = null;
repaint();
}
}
}
public CirclePanel() {
MouseHelper helper = new MouseHelper();
addMouseListener(helper);
addMouseMotionListener(helper);
setPreferredSize(new Dimension(400, 400));
}
#Override
public void paint(Graphics g) {
g.setColor(backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(oldCircleColor);
for (Circle c : oldCircles) {
drawCircle(g, c);
}
Circle c = newCircle;
if (c != null) {
g.setColor(newCircleColor);
drawCircle(g, c);
Graphics2D g2 = (Graphics2D) g.create();
g2.setStroke(DASHED);
g2.drawLine(c.x, c.y, mouseX, mouseY);
g2.dispose();
}
}
private void drawCircle(Graphics g, Circle c) {
// note: drawOval takes top-left corner and diameter, NOT center and radius
g.drawOval(c.x - c.radius, c.y - c.radius, c.radius * 2, c.radius * 2);
}
}
And test to see that it works
public static void main(String[] args) {
JFrame frame = new JFrame();
CirclePanel panel = new CirclePanel();
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
Like #SirLenz0rlot mentioned in the comments there is a bug in your moveTo method. The problem is the call circleList.get(circleList.size() - 1).setCords(tempX, tempY, tempR); which is setting the position of the circle to tempX, tempY, but you probably only want to set the radius of the circle, while the coords are not changed.
Changing the moveTo method to the code below should help:
public void moveTo(int x, int y)
{
var circleTemp = circleList.get(circleList.size() - 1);
isDraged = true;
var tempR = (int)Math.sqrt(Math.pow(x - circleTemp.get(0), 2) + Math.pow(y - circleTemp.get(1), 2));
System.out.println(tempR);
var tempX = circleTemp.get(0) - (tempR / 2);
var tempY = circleTemp.get(1) - (tempR / 2);
//EDITED HERE
circleList.get(circleList.size() - 1).setCords(circleTemp.get(0), circleTemp.get(1), tempR);//using getX() and getY() on your circle would be easier to understand here, but this should also work...
lineX = x;
lineY = y;
repaint();
}
For some reason your circleTemp.get(0) and (1) doesn't give you the (x,y) coordinates
circleTemp.get(0)
What you should do is save the circle's (x,y) coordinates, and use them in the moveTo method.
Correct Change
And in the end for the draw line, you should again, use the saved (x,y) coordinates and the new coordinated of the mouse. (not the circleList.size() -1).get(0) - Line 67)
(Ex. I added the drawLineX and drawLineY)
I'm new to Java and I am trying to make a simple paint program where the user presses button to draw lines by mouse dragging
My problem is that lines aren't drawn on canvas although the properties of each line are saved.
When I try to draw line in the method of "mouse released" it works so I suppose that the problem is with "PaintComponent" but I can't find it.
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
public class GUI extends JPanel{
public JFrame frame = new JFrame();
public Canvas canvas = new Canvas();
private Point p1,p2;
private List<pro> lineList = new ArrayList<>();
private pro currentLine = null;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI window = new GUI();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public GUI() {
initialize();
}
public void paintComponent(Graphics page) {
super.paintComponent(page);
for (pro line : lineList) {
line.draw(page);
System.out.println(line);
}
if (currentLine != null) {
currentLine.draw(page);
}
}
private void initialize(){
frame.getContentPane().setBackground(Color.BLACK);
frame.setBounds(0, 0, 346, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(canvas);
Canvas canvas = new Canvas();
canvas.setLocation(10, 10);
canvas.setSize(200, 241);
canvas.setBackground(Color.DARK_GRAY);
frame.getContentPane().add(canvas);
JButton btnLine = new JButton("Line");
frame.getContentPane().add(btnLine);
btnLine.setBackground(Color.DARK_GRAY);
btnLine.setForeground(Color.RED);
btnLine.setFont(new Font("Stencil", Font.BOLD, 16));
btnLine.addActionListener(new ActionListener() {
int x1;
int y1;
public void actionPerformed(ActionEvent e) {
canvas.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
}
public void mouseReleased(MouseEvent e) {
pro line = createLine(e,Color.red);
lineList.add(line);
currentLine = null;
canvas.repaint();
}
});
canvas.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, Color.white);
repaint();
}
});
}
private pro createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new pro(x1, x2, y1, y2, currentColor);
}
});
btnLine.setBounds(229, 95, 91, 31);
frame.getContentPane().add(btnLine);
}
class pro {
private int x1, x2, y1, y2;
private Color color;
public pro(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.setColor(color);
page.drawLine(x1, y1, x2, y2);
}
}
}
JFrames are not meant to override paintComponent: they're multi-layered containers. If you want to paint a custom component, create a subclass of JComponent (or JPanel), and then put it in (the content pane of) your JFrame.
This works for me:
public class SketchPad extends JComponent {
private final List<Line> lineList = new ArrayList<>();
private Line currentLine = null;
private Color drawingColor = Color.RED;
public SketchPad() {
initialize();
}
public Color getDrawingColor() {
return drawingColor;
}
public void setDrawingColor(Color newColor) {
if (newColor == null) {
throw new IllegalArgumentException("Drawing color cannot be null");
}
this.drawingColor = newColor;
}
private void initialize() {
addMouseListener(new MouseAdapter() {
int x1;
int y1;
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
}
#Override
public void mouseReleased(MouseEvent e) {
Line line = createLine(e, drawingColor);
lineList.add(line);
currentLine = null;
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
currentLine = createLine(e, Color.BLACK);
repaint();
}
private Line createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new Line(x1, x2, y1, y2, currentColor);
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Line line : lineList) {
line.draw(g);
System.out.println(line);
}
if (currentLine != null) {
currentLine.draw(g);
}
}
private static class Line {
private final int x1;
private final int x2;
private final int y1;
private final int y2;
private final 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.setColor(color); //!! This first!
page.drawLine(x1, y1, x2, y2); // **Then** this
}
}
}
Main frame:
public class MainFrame extends javax.swing.JFrame {
private SketchPad pad;
public MainFrame() {
initComponents();
}
#SuppressWarnings("unchecked")
private void initComponents() {
pad = new SketchPad();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().add(pad, java.awt.BorderLayout.CENTER);
pack();
}
}
UPDATE: a mouseMotionListener is needed:
private void initialize() {
MouseAdapter adapter = new MouseAdapter() {
int x1;
int y1;
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
addMouseMotionListener(this);
}
#Override
public void mouseReleased(MouseEvent e) {
Line line = createLine(e, drawingColor);
lineList.add(line);
currentLine = null;
repaint();
removeMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, Color.BLACK);
repaint();
}
private Line createLine(MouseEvent e, Color currentColor) {
int x2 = e.getX();
int y2 = e.getY();
return new Line(x1, x2, y1, y2, currentColor);
}
};
addMouseListener(adapter);
addMouseMotionListener(adapter);
}
UPDATE 2: handle enable/disable
private final MouseAdapter adapter = new MouseAdapter() {
int x1;
int y1;
#Override
public void mousePressed(MouseEvent e) {
x1 = e.getX();
y1 = e.getY();
currentLine = null;
}
#Override
public void mouseReleased(MouseEvent e) {
Line line = createLine(e, drawingColor);
lineList.add(line);
currentLine = null;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
currentLine = createLine(e, Color.BLACK);
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 void initialize() {
setEnabled(isEnabled());
}
...
#Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (enabled) {
addMouseListener(adapter);
addMouseMotionListener(adapter);
} else {
removeMouseListener(adapter);
removeMouseMotionListener(adapter);
}
}
So, I have a program where I can add shapes to JPanel using Path2D objects and then I can click and drag them around. What I want to do is be able to find the final X and Y coordinates of the shape AFTER it has been drug. The coordinates need to be the top-left coordinates. Any ideas?
// add a circle to center of the screen
public void addCircle(int width, int height) {
Path2D circ = new Path2D.Double();
circ.append(new Ellipse2D.Double(getWidth() / 2 - width / 2,
getHeight() / 2 - height / 2, width, height), true);
shapes.add(circ);
repaint();
}
..................
//paint all shapes
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setOpaque(true);
this.setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(2));
for (Path2D shape : shapes) {
g2.draw(shape);
}
}
..................
// if the mouse click is in the circle, set pressed=true
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
if (shapes.get(i) != null
&& shapes.get(i).contains(e.getPoint())) {
currentIndex = i;
pressed = true;
this.point = e.getPoint();
}
}
}
//if pressed=true, move circle with mouse
#Override
public void mouseDragged(MouseEvent e) {
if (pressed && !lineSelected) {
int deltaX = e.getX() - point.x;
int deltaY = e.getY() - point.y;
shapes.get(currentIndex).transform(
AffineTransform.getTranslateInstance(deltaX, deltaY));
point = e.getPoint();
//I need to find the new coordinates here!!!!!!!!!!!
repaint();
}
}
Full Code
class Canvas extends JPanel {
private static final long serialVersionUID = 1L;
private List<Path2D> shapes = new ArrayList<Path2D>();
private int currentIndex;
private Point lineStartingPoint = new Point();
private Point lineEndingPoint = new Point();
private boolean drawing;
private boolean lineSelected;
private Path2D.Double linePath;
private Shapes myShapes = new Shapes();
private List<Path2D> circles = new ArrayList<Path2D>();
public Canvas() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
public void setList(ArrayList<UMLCircle> shapes) {
}
public List<UMLCircle> getList() {
return null;
}
public void addSquare(int width, int height) {
Path2D rect2 = new Path2D.Double();
rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
- height / 2, width, height), true);
shapes.add(rect2);
repaint();
}
public void addLine() {
lineSelected = true;
repaint();
}
public void addCircle(int width, int height) {
myShapes.addCircle(getWidth() / 2 - width / 2, getHeight() / 2 - height
/ 2, width, height);
Path2D circ = new Path2D.Double();
circ.append(new Ellipse2D.Double(getWidth() / 2 - width / 2,
getHeight() / 2 - height / 2, width, height), true);
circles.add(circ);
shapes.add(circ);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setOpaque(true);
this.setBackground(Color.WHITE);
Graphics2D g2 = (Graphics2D) g;
if (lineSelected) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(2));
g2.drawLine(lineStartingPoint.x, lineStartingPoint.y,
lineEndingPoint.x, lineEndingPoint.y);
}
g2.setStroke(new BasicStroke(2));
for (Path2D shape : shapes) {
g2.draw(shape);
}
}
class MyMouseAdapter extends MouseAdapter {
private boolean pressed = false;
private Point point;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
for (int i = 0; i < shapes.size(); i++) {
if (shapes.get(i) != null
&& shapes.get(i).contains(e.getPoint())) {
currentIndex = i;
pressed = true;
this.point = e.getPoint();
}
if (circles.get(i) != null
&& circles.get(i).contains(e.getPoint())) {
currentIndex = i;
pressed = true;
this.point = e.getPoint();
}
}
if (lineSelected) {
drawing = true;
lineStartingPoint = e.getPoint();
lineEndingPoint = lineStartingPoint;
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (pressed && !lineSelected) {
int deltaX = e.getX() - point.x;
int deltaY = e.getY() - point.y;
shapes.get(currentIndex).transform(
AffineTransform.getTranslateInstance(deltaX, deltaY));
point = e.getPoint();
myShapes.updateCircleLocation(currentIndex, point.x, point.y);
System.out.println(point.x + " " + point.y);
repaint();
}
if (drawing) {
lineEndingPoint = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (drawing && lineSelected) {
drawing = false;
lineSelected = false;
lineEndingPoint = e.getPoint();
linePath = new Path2D.Double();
linePath.moveTo(lineStartingPoint.getX(),
lineStartingPoint.getY());
linePath.lineTo(lineEndingPoint.getX(), lineEndingPoint.getY());
shapes.add(linePath);
repaint();
}
pressed = false;
}
}
}
EDIT
Calculation for offset:
int deltaX = e.getX() - point.x;
int deltaY = e.getY() - point.y;
shapes.get(currentIndex).transform(
AffineTransform.getTranslateInstance(deltaX, deltaY));
point = e.getPoint();
int newXPos = e.getX() - deltaX; // final X pos
int newXPos = e.getX() - deltaX; // final Y pos
Before you can do anything, you need to know the offset of the mouse click from the corner of the shape, this will allow you to drag the object so it doesn't suddenly "jump" to your current mouse position...
#Override
public void mousePressed(MouseEvent e) {
//...
for (Shape shape : myShapes) {
//...
this.point = e.getPoint();
int deltaX = point.x - shape.getBounds().x;
int deltaY = point.y - shape.getBounds().y;
offset = new Point(deltaX, deltaY);
//...
}
}
}
Then, you would calculate the delta of change, between the current mouse position and the offset. Because you're applying a translate, you also need to subtract the shape's current location, as the translation is based on the shape's current location and we only want to apply the amount of change
#Override
public void mouseDragged(MouseEvent e) {
if (pressed) {
int index = myShapes.indexOf(clickedShape);
myShapes.remove(index);
int deltaX = e.getPoint().x - offset.x;
int deltaY = e.getPoint().y - offset.y;
clickedShape = new Path2D.Double(clickedShape,
AffineTransform.getTranslateInstance(
deltaX - clickedShape.getBounds().x,
deltaY - clickedShape.getBounds().y));
myShapes.add(index, clickedShape);
point = e.getPoint();
repaint();
}
}
Now, having said all that, don't do this...
protected void paintComponent(Graphics g) {
//...
this.setOpaque(true);
this.setBackground(Color.WHITE);
Changing the state of the component from within the paint method can setup a infinite loop of repaint requests, which can chock your system. Also, the changes you make won't be applied to the current graphics context, as these properties are generally applied by the paint method...
And a working copy....
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
class Canvas extends JPanel {
private static final long serialVersionUID = 1L;
private boolean drawing;
private List<Shape> myShapes = new ArrayList<Shape>();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Canvas());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public Canvas() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
addSquare(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void setList(ArrayList<Shape> shapes) {
}
public List<Shape> getList() {
return null;
}
public void addSquare(int width, int height) {
Path2D rect2 = new Path2D.Double();
rect2.append(new Rectangle(getWidth() / 2 - width / 2, getHeight() / 2
- height / 2, width, height), true);
myShapes.add(rect2);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(2));
for (Shape shape : myShapes) {
g2.draw(shape);
}
}
class MyMouseAdapter extends MouseAdapter {
private boolean pressed = false;
private Point point;
private Point offset;
private Shape clickedShape;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
for (Shape shape : myShapes) {
if (shape != null
&& shape.contains(e.getPoint())) {
System.out.println("Clicked");
pressed = true;
clickedShape = shape;
this.point = e.getPoint();
int deltaX = point.x - shape.getBounds().x;
int deltaY = point.y - shape.getBounds().y;
offset = new Point(deltaX, deltaY);
System.out.println(point + "x" + offset);
repaint();
break;
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (pressed) {
int index = myShapes.indexOf(clickedShape);
myShapes.remove(index);
int deltaX = e.getPoint().x - offset.x;
int deltaY = e.getPoint().y - offset.y;
clickedShape = new Path2D.Double(clickedShape,
AffineTransform.getTranslateInstance(
deltaX - clickedShape.getBounds().x,
deltaY - clickedShape.getBounds().y));
myShapes.add(index, clickedShape);
point = e.getPoint();
repaint();
}
}
#Override
public void mouseReleased(MouseEvent e) {
offset = null;
pressed = false;
}
}
}
So I'm creating a free hand drawing JPanel, that reacts to mouse movements and draws lines. I got it mostly working except for a bug where it'll randomly draw a straight line between lines. That random straight line isn't intentional, what's drawn on the buffered image is supposed to be strictly what the user draws. These random drawn lines are not done by the user and it's confusing. Below is my code, can anyone take a look? The image included gives you a visual representation of what it is doing.
public class NoteDocument extends JPanel implements MouseListener, MouseMotionListener {
private Frame commands;
private JDesktopPane desktop;
private JInternalFrame colorFrame;
private JPanel colorPanel;
private JColorChooser colorChooser;
private enum State { IDLING, DRAGGING };
private enum ButtonPosition { PRESSED, RELEASED };
private enum Shape { SQUARE, RECTANGLE, CIRCLE, OVAL, LINE };
private State state = State.IDLING;
private ButtonPosition position = ButtonPosition.RELEASED;
private Shape shape = null;
//private ArrayList<Point> points = new ArrayList<Point>();
private ArrayList<Point> pressedPoints = new ArrayList<Point>();
private ArrayList<Point> draggedPoints = new ArrayList<Point>();
private ArrayList<Point> releasedPoints = new ArrayList<Point>();
private BufferedImage bufferedImage = null;
public NoteDocument(Frame commands) {
this.commands = commands;
setBackground(Color.WHITE);
addMouseListener(this);
addMouseMotionListener(this);
createColorChooser();
}
private void createColorChooser() {
for (int i = 0; i < commands.getLayeredPane().getComponentCount(); i++) {
if (commands.getLayeredPane().getComponent(i) instanceof JDesktopPane) {
desktop = (JDesktopPane) commands.getLayeredPane().getComponent(i);
}
}
colorChooser = new JColorChooser();
colorPanel = new JPanel();
colorFrame = new JInternalFrame();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(colorPanel);
colorPanel.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(colorChooser, javax.swing.GroupLayout.PREFERRED_SIZE, 434, javax.swing.GroupLayout.PREFERRED_SIZE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(colorChooser, javax.swing.GroupLayout.PREFERRED_SIZE, 328, javax.swing.GroupLayout.PREFERRED_SIZE)
);
colorFrame.add(colorPanel);
desktop.add(colorFrame);
colorFrame.pack();
colorFrame.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if(bufferedImage == null)
{
int panelHeight = this.getHeight();
int panelWidth = this.getWidth();
bufferedImage = (BufferedImage) this.createImage(panelHeight, panelWidth);
Graphics2D gc = bufferedImage.createGraphics();
gc.setColor(Color.WHITE);
gc.fillRect(0, 0, panelWidth, panelHeight);
g2.drawImage(bufferedImage, null, 0, 0);
}
//draw pressed points
for (int a = 0; a < pressedPoints.size(); a++) {
Point p1 = pressedPoints.get(a);
g.drawLine(p1.x, p1.y, p1.x, p1.y);
}
//draw draggedPoints
for (int b = 0; b < draggedPoints.size() - 2; b++) {
Point p1 = draggedPoints.get(b);
Point p2 = draggedPoints.get(b + 1);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
//draw released points
for (int c = 0; c < releasedPoints.size(); c++) {
Point p1 = releasedPoints.get(c);
g.drawLine(p1.x, p1.y, p1.x, p1.y);
}
}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
position = ButtonPosition.PRESSED;
state = State.DRAGGING;
pressedPoints.add(e.getPoint());
this.repaint();
} else if (e.getButton() == MouseEvent.BUTTON2) {
//TODO right click popup
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (state == State.DRAGGING) {
releasedPoints.add(e.getPoint());
position = ButtonPosition.RELEASED;
state = State.IDLING;
this.repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if ((state == State.DRAGGING) && (position == ButtonPosition.PRESSED)) {
draggedPoints.add(e.getPoint());
this.repaint();
} else if ((state == State.IDLING) && (position == ButtonPosition.RELEASED)) {
return;
}
}
#Override
public void mouseMoved(MouseEvent e) {
if ((state == State.DRAGGING) && (position == ButtonPosition.PRESSED)) {
draggedPoints.add(e.getPoint());
this.repaint();
} else if ((state == State.IDLING) && (position == ButtonPosition.RELEASED)) {
return;
}
}
}
You will likely want to nest Lists to achieve your goal:
List<List<Point>>
This way, when the mouse is pressed, start an ArrayList, and when released, finish it. Then you can use nested for loops to draw all the curves.
For example (from a previous answer of mine):
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
public class LineDrawEg {
private static void createAndShowGui() {
JPanel mainPanel = new JPanel(new GridLayout(1, 0));
mainPanel.setPreferredSize(new Dimension(800, 400));
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
JPanel[] panels = {new Panel1(), new Panel2()};
for (int i = 0; i < panels.length; i++) {
String title = "Panel " + (i + 1);
Border border = new TitledBorder(title);
panels[i].setBorder(border);
panels[i].addMouseListener(mouseAdapter);
panels[i].addMouseMotionListener(mouseAdapter);
mainPanel.add(panels[i]);
}
JFrame frame = new JFrame("Line Draw Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Panel1 extends JPanel implements Positionable {
private int xPos = 0;
private int yPos = 0;
#Override
protected void paintComponent(Graphics g) {
// super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(xPos, yPos, 5, 5);
}
#Override
public void mouseDragged(Point p) {
xPos = p.x;
yPos = p.y;
repaint();
}
#Override
public void mousePressed(Point p) {
xPos = p.x;
yPos = p.y;
repaint();
}
#Override
public void mouseReleased(Point p) {
xPos = p.x;
yPos = p.y;
repaint();
}
}
class Panel2 extends JPanel implements Positionable {
private List<List<Point>> listOfLists = new ArrayList<List<Point>>();
private List<Point> currentPoints;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5f));
if (currentPoints != null && currentPoints.size() > 1) {
g2.setColor(Color.blue);
for (int i = 1; i < currentPoints.size(); i++) {
int x1 = currentPoints.get(i - 1).x;
int y1 = currentPoints.get(i - 1).y;
int x2 = currentPoints.get(i).x;
int y2 = currentPoints.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
}
g2.setColor(Color.red);
for (List<Point> pointList : listOfLists) {
if (pointList.size() > 1) {
for (int i = 1; i < pointList.size(); i++) {
int x1 = pointList.get(i - 1).x;
int y1 = pointList.get(i - 1).y;
int x2 = pointList.get(i).x;
int y2 = pointList.get(i).y;
g2.drawLine(x1, y1, x2, y2);
}
}
}
}
#Override
public void mousePressed(Point p) {
currentPoints = new ArrayList<Point>();
currentPoints.add(p);
repaint();
}
#Override
public void mouseDragged(Point p) {
currentPoints.add(p);
repaint();
}
#Override
public void mouseReleased(Point p) {
if (currentPoints != null) {
currentPoints.add(p);
listOfLists.add(currentPoints);
}
currentPoints = null;
repaint();
}
}
class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseDragged(MouseEvent mEvt) {
Positionable positionable = (Positionable) mEvt.getSource();
positionable.mouseDragged(mEvt.getPoint());
}
#Override
public void mousePressed(MouseEvent mEvt) {
Positionable positionable = (Positionable) mEvt.getSource();
positionable.mousePressed(mEvt.getPoint());
}
#Override
public void mouseReleased(MouseEvent mEvt) {
Positionable positionable = (Positionable) mEvt.getSource();
positionable.mouseReleased(mEvt.getPoint());
}
}
interface Positionable {
void mouseDragged(Point p);
void mousePressed(Point p);
void mouseReleased(Point p);
}
How to draw circle on mouse dragged event, and then how to move that circle on mouse dragged event in Java?
My code is below.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class r extends JPanel {
public int x1, x2, y1, y2, r, w, h,xDist,yDist;
public static boolean flag = false, pressFlag = false;
public r() {
setBackground(Color.WHITE);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent m) {
// pressFlag = true;
if (r > (int) Math.sqrt(Math.abs(m.getX() - x1) * Math.abs(m.getX() - x1) + Math.abs(m.getY() - y1) * Math.abs(m.getY() - y1))) {
flag = true;
yDist=xDist=x2 = y2 = 0;
} else {
x1 = y1 = 0;
r=x2 = y2 = 0;
x1 = m.getX();
y1 = m.getY();
}
repaint();
}
public void mouseReleased(MouseEvent m) {
w = x2 - x1;
h = y2 - y1;
r = (int) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
flag = false;
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent m) {
if (flag && (x2!=0 && y2!=0)) {
xDist=(m.getX()-x2);
yDist=(m.getY()-y2);
}
x2 = m.getX();
y2 = m.getY();
repaint();
}
});
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (flag) {
x1=x1+xDist;
y1=y1+yDist;
g.drawOval(x1, y1, w, h);
} else {
g.drawOval(x1, y1, x2 - x1, y2 - y1);
}
}
}
public class q extends JFrame {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(300, 300);
jFrame.add(new r());
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Something along those lines works nicely for me:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
class DragCircle extends JPanel {
private final class MouseDrag extends MouseAdapter {
private boolean dragging = false;
private Point last;
#Override
public void mousePressed(MouseEvent m) {
last = m.getPoint();
dragging = isInsideEllipse(last);
if (!dragging) {
x = last.x;
y = last.y;
width = 0;
height = 0;
}
repaint();
}
#Override
public void mouseReleased(MouseEvent m) {
last = null;
dragging = false;
repaint();
}
#Override
public void mouseDragged(MouseEvent m) {
int dx = m.getX() - last.x;
int dy = m.getY() - last.y;
if (dragging) {
x += dx;
y += dy;
} else {
width += dx;
height += dy;
}
last = m.getPoint();
repaint();
}
}
private int x;
private int y;
private int width;
private int height;
private MouseDrag mouseDrag;
public DragCircle() {
setBackground(Color.WHITE);
mouseDrag = new MouseDrag();
addMouseListener(mouseDrag);
addMouseMotionListener(mouseDrag);
}
public boolean isInsideEllipse(Point point) {
return new Ellipse2D.Float(x, y, width, height).contains(point);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawOval(x, y, width, height);
}
public static void main(String[] args) {
JFrame jFrame = new JFrame();
jFrame.setSize(300, 300);
jFrame.add(new DragCircle());
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}