Reputation: 33
I am trying to write a program that will draw a circle on a mouse click with the circle centered to the coordinates of my mouse click. My circle will be 50 by 50. In my mouse-listener class, I am offsetting by x-25 and y-25 however, the circle does not appear centered to my click. It appears slightly below the click.
public class CircleDraw extends JPanel
private JFrame frame;
private JPanel P1;
private int circlecount;
private int x, y;
MouseClicks minney;
ArrayList<Circle> circles = new ArrayList<Circle>();
public CircleDraw()
{
frame = new JFrame("CircleDraw");
frame.setSize(800,800);
minney = new MouseClicks();
//circles.add(new Circle(x,y));//This may be the original circle being added
this.setBackground(Color.BLACK);
this.setPreferredSize(new Dimension(800,800));
frame.add(this);
frame.pack();
frame.setVisible(true);
frame.addMouseListener(minney);
}
public class Circle
{
int x, y;
public Circle(int x, int y)
{
this.x = x; this.y = y;
}
public void draw(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.GREEN);
g2d.fillOval(x,y,50,50);
}
}
@Override
protected void paintComponent(Graphics g)
{
{
super.paintComponent(g);
for (Circle c : circles)
c.draw(g);
}
}
public class MouseClicks implements MouseListener
{
int x, y, b;
public void mouseClicked(MouseEvent m)
{
int x = m.getX(), y = m.getY(); b = m.getButton();
this.x = x;
this.y = y;
{
circles.add(new Circle(x-25, y-25));
CircleDraw.this.repaint();
}
}
public void mouseEntered(MouseEvent m) {}
public void mouseExited(MouseEvent m) {}
public void mousePressed(MouseEvent m) {}
public void mouseReleased(MouseEvent m) {}
}
}
Upvotes: 0
Views: 449
Reputation: 285405
You're adding the MouseListener to the wrong component. Here:
frame.addMouseListener(minney);
You're adding it to the JFrame, which will translate the mouse coordinates down by the distance of the JFrame's header bar, when you need to be adding it to the component that is actually doing the drawing, the this
so that the mouse press coordinates match the drawing coordinates:
addMouseListener(minney);
or explicitly
this.addMouseListener(minney);
For example, code similar to yours with draggable circles:
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.Shape;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class CircleDraw2 extends JPanel {
private static final int CIRCLE_RADIUS = 25;
private static final Color BACKGROUND = Color.BLACK;
private int prefW;
private int prefH;
List<Circle2> circles = new ArrayList<>();
public CircleDraw2(int prefW, int prefH) {
this.prefW = prefW;
this.prefH = prefH;
setBackground(BACKGROUND);
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Circle2 circle : circles) {
circle.draw(g2);
}
}
private class MyMouse extends MouseAdapter {
private Point p0 = null;
private Circle2 selection = null;
@Override
public void mousePressed(MouseEvent e) {
for (int i = circles.size() - 1; i >= 0; i--) {
if (circles.get(i).contains(e.getPoint())) {
// if mouse clicks on a circle that already exists
p0 = e.getPoint();
selection = circles.get(i); // select that pressed circle
// move it to the top
circles.remove(selection);
circles.add(selection);
repaint();
return;
}
}
// no circle selected, so create a new one
int centerX = e.getX();
int centerY = e.getY();
Color c = createRandomColor();
selection = new Circle2(centerX, centerY, CIRCLE_RADIUS, c);
circles.add(selection);
p0 = e.getPoint();
repaint();
}
private Color createRandomColor() {
double minRand = 0.7; // min saturation and brightness
float hue = (float) Math.random();
float saturation = (float)((1 - minRand) * Math.random() + minRand);
float brightness = (float)((1 - minRand) * Math.random() + minRand);
Color c = Color.getHSBColor(hue, saturation, brightness);
return c;
}
private void drag(Point p1) {
if (p0 == null) {
return;
}
selection.move(p0, p1);
p0 = p1;
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
drag(e.getPoint());
}
@Override
public void mouseReleased(MouseEvent e) {
drag(e.getPoint());
p0 = null;
selection = null;
}
}
private static void createAndShowGui() {
int width = 800;
int height = width;
CircleDraw2 mainPanel = new CircleDraw2(width, height);
JFrame frame = new JFrame("CircleDraw2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Circle2 {
private Color color;
private Path2D path; // easily moveable with affine transform
public Circle2(int centerX, int centerY, int radius, Color color) {
this.color = color;
double x = centerX - radius;
double y = centerY - radius;
double w = 2 * radius;
double h = w;
Ellipse2D e2d = new Ellipse2D.Double(x, y, w, h);
path = new Path2D.Double(e2d);
}
public void move(Point p0, Point p1) {
// get the distance or "delta" of the move
int deltaX = p1.x - p0.x;
int deltaY = p1.y - p0.y;
// move the circle delta amount
path.transform(AffineTransform.getTranslateInstance(deltaX, deltaY));
}
public void draw(Graphics2D g2) {
g2.setColor(color);
g2.fill(path);
g2.setColor(Color.BLACK);
g2.draw(path);
}
public int getCenterX() {
return (int) path.getBounds().getCenterX();
}
public int getCenterY() {
return (int) path.getBounds().getCenterY();
}
public int getRadius() {
return (int) path.getBounds().getWidth() / 2;
}
public Color getColor() {
return color;
}
public Shape getEllipse() {
return path;
}
public boolean contains(Point p) {
return path.contains(p);
}
}
Upvotes: 1