简体   繁体   中英

Why does my mouse event coordinates return wrong values?

I've got two classes: Connection extends JComponent and PostMachineView extends JPanel implements MouseListener . What I'm trying to do is fire a method whenever the mouse button is pressed inside the Connection component. I'm using SwingUtilities.convertPointToScreen so that the mouse event coordinates will be relative to where I am drawing. The problem is that it returns slightly different numbers for x and y than it should. Code below:

public class PostMachineView extends JPanel implements MouseListener {
    ArrayList<Connection> connections;

    public PostMachineView() {
        connections = new ArrayList<>();
        setSize(new Dimension(800, 800));
        setBackground(Color.white);

        //here i create the points i'll need for the connection and instantiate it
        Point p1 = new Point(100, 100);
        Point p2 = new Point(100, 200);
        Connection conn = new Connection(p1, p2);
        //add the connection component to this panel
        add(conn);
        //set the connection mouse listener
        conn.addMouseListener(this);

        connections.add(conn);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);

        //this will be done in a different way, just trying to get it to work first
         Point p1 = new Point(100, 100);
         Point p2 = new Point(100, 200);

         ((Connection)getComponent(0)).paintComponent(g, p1, p2);
    }

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        System.out.println("clicked in the component");
    }

    @Override
    public void mouseReleased(MouseEvent e) {}
}

public class Connection extends JComponent {

    private Rectangle2D.Double curveControl;
    private GeneralPath path;

    public Connection(Point p1, Point p2) {
        path = new GeneralPath();
        path.moveTo(p1.getX(), p1.getY());
        int[] mid = getMidPointCoords(p1, p2);
        curveControl = new Rectangle2D.Double(mid[0] - 5, mid[1] - 5, 10, 10);
        path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
                curveControl.getCenterX(), curveControl.getCenterY(),
                p2.getX(), p2.getY());

    }
    public int[] getMidPointCoords(Point p1, Point p2) {
        int[] v = { 0, 0 };
        v[0] = (int) ((p1.getX() + p2.getX()) / 2);
        v[1] = (int) ((p1.getY() + p2.getY()) / 2);
        return v;
    }

    public void paintComponent(Graphics g, Point p1, Point p2) {
        path.moveTo(p1.getX(), p1.getY());
        path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
                curveControl.getCenterX(), curveControl.getCenterY(),
                p2.getX(), p2.getY());

        Graphics2D g2d = (Graphics2D) g;

        g2d.draw(path);
        g2d.setColor(Color.red);
        g2d.fill(curveControl);
        g2d.setColor(Color.black);
    }

    @Override
    public boolean contains(int x, int y) {
    //here is where i use swingutilities to convert the coordinates
        Point p = new Point(x, y);
        SwingUtilities.convertPointToScreen(p, this);
        return curveControl.contains(p.getX(), p.getY());
    }
}

I also have a Teste class, which simply instantiates a JFrame and adds a PostMachineView to it:

public class Teste  {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setSize(new Dimension(800,800));
        f.add(new PostMachineView());
        f.setResizable(false);
        f.setVisible(true);
    }
}

This...

public void paint(Graphics g) {
    super.paint(g);

    //this will be done in a different way, just trying to get it to work first
     Point p1 = new Point(100, 100);
     Point p2 = new Point(100, 200);

     ((Connection)getComponent(0)).paintComponent(g, p1, p2);
}

Is a VERY bad idea. The Connection component is already a child of the PostMachineView component. You should simply be updating the state of Connection (maybe through a mouseClicked event) and calling repaint to update it.

In Connection , this...

public void paintComponent(Graphics g, Point p1, Point p2) {
    path.moveTo(p1.getX(), p1.getY());
    path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
            curveControl.getCenterX(), curveControl.getCenterY(),
            p2.getX(), p2.getY());

    Graphics2D g2d = (Graphics2D) g;

    g2d.draw(path);
    g2d.setColor(Color.red);
    g2d.fill(curveControl);
    g2d.setColor(Color.black);
}

Should be slit into two methods, one that adds the new point and one that draws it...

public void add(Point p1, Point p2) {
    path.moveTo(p1.getX(), p1.getY());
    path.curveTo(curveControl.getCenterX(), curveControl.getCenterY(),
                    curveControl.getCenterX(), curveControl.getCenterY(),
                    p2.getX(), p2.getY());
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    g2d.draw(path);
    g2d.setColor(Color.red);
    g2d.fill(curveControl);
    g2d.setColor(Color.black);
    g2d.dispose();
}

Because the MouseListener is attached to the Connection component, this...

@Override
public boolean contains(int x, int y) {
//here is where i use swingutilities to convert the coordinates
    Point p = new Point(x, y);
    SwingUtilities.convertPointToScreen(p, this);
    return curveControl.contains(p.getX(), p.getY());
}

No longer makes sense and, to be honest, I'd be VERY careful with messing around with this

At best it should be more like...

public boolean contains(int x, int y) {
    return curveControl.contains(x, y);
}

But remember, the MouseListener will no longer generate events unless the x/y coordinates are WITHIN the curveControl , which might not really be what you want.

Oh and this ArrayList<Connection> connections; scares me...but then, I don't have the context to your problem to really know what you're intentions are for this...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM