Sensing hover over outer edge of a Path2D circle in JPanel [duplicate]

假如想象 提交于 2019-12-02 07:42:26

You'll want to brush up your trig (or google search like I did ;)). The basic concept is "relatively" easy, but I created a nice method to all the work for me...

This method...

public Point2D getPointOnEdge(float angel, Rectangle bounds) {

    float radius = Math.max(bounds.width, bounds.height) / 2;

    float x = radius;
    float y = radius;

    double rads = Math.toRadians((angel + 90));

    // Calculate the outter point of the line
    float xPosy = (float) (x + Math.cos(rads) * radius);
    float yPosy = (float) (y + Math.sin(rads) * radius);

    return new Point2D.Float(xPosy + bounds.x, yPosy + bounds.y);

}

Will calculate the x/y point that a given angle will appear on a circle, remember, this will ONLY work for circles!

I then use another method...

public Rectangle2D getActiveBounds(float angel, Rectangle bounds) {

    Point2D p = getPointOnEdge(angel, bounds);

    return new Rectangle2D.Double(p.getX() - 4, p.getY() - 4, 8, 8);

}

To calculate the "mouse zone" in which I would consider to be the bottom/right area, cause a single pixel is hard to find and simply use Rectangle#contains, passing it the current mouse location...

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Editor {

    public static void main(String[] args) {
        new Editor();
    }

    public Editor() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new UMLWindow();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setBounds(30, 30, 1000, 700);
                frame.getContentPane().setBackground(Color.white);
                frame.setVisible(true);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class UMLWindow extends JFrame {

        Shapes shapeList = new Shapes();
        Panel panel;

        private static final long serialVersionUID = 1L;

        public UMLWindow() {
            addMenus();
            panel = new Panel();
        }

        public void addMenus() {

            getContentPane().add(shapeList);

            setSize(300, 200);
            setLocationRelativeTo(null);
            setDefaultCloseOperation(EXIT_ON_CLOSE);

            shapeList.addCircle(100, 100);
        }
    }

// Shapes class, used to draw the shapes on the panel
// as well as implements the MouseListener for dragging
    public static class Shapes extends JPanel {

        private static final long serialVersionUID = 1L;

        private List<Path2D> shapes = new ArrayList<Path2D>();
        int currentIndex;

        private Point mousePoint;

        public Shapes() {
            MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
            addMouseListener(myMouseAdapter);
            addMouseMotionListener(myMouseAdapter);
        }

        public void addCircle(int width, int height) {
            Path2D circ = new Path2D.Double();
            circ.append(new Ellipse2D.Double(442, 269, width, height), true);
            shapes.add(circ);
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2 = (Graphics2D) g;
            g2.setStroke(new BasicStroke(2));
            for (Path2D shape : shapes) {
                g2.setColor(Color.BLACK);
                g2.draw(shape);

                g2.setColor(Color.RED);
                Rectangle2D bottomRight = getActiveBounds(-45, shape.getBounds());

                g2.draw(bottomRight);
                if (mousePoint != null) {

                    if (bottomRight.contains(mousePoint)) {
                        g2.fill(bottomRight);
                    }

                }

            }
        }

        public Rectangle2D getActiveBounds(float angel, Rectangle bounds) {

            Point2D p = getPointOnEdge(angel, bounds);

            return new Rectangle2D.Double(p.getX() - 4, p.getY() - 4, 8, 8);

        }

        public Point2D getPointOnEdge(float angel, Rectangle bounds) {

            float radius = Math.max(bounds.width, bounds.height) / 2;

            float x = radius;
            float y = radius;

            double rads = Math.toRadians((angel + 90));

            // Calculate the outter point of the line
            float xPosy = (float) (x + Math.cos(rads) * radius);
            float yPosy = (float) (y + Math.sin(rads) * radius);

            return new Point2D.Float(xPosy + bounds.x, yPosy + bounds.y);

        }

        class MyMouseAdapter extends MouseAdapter {

            @Override
            public void mouseMoved(MouseEvent e) {
                mousePoint = e.getPoint();
                repaint();
            }

        }
    }

}

This example does all the work within the paint method, because I wanted to see the "area of effect", you can easily use the same logic to change the mouse cursor within the MouseMoitionListener

Not sure if this will work but you can try something like:

  1. Create a Shape circle that is a couple of pixels smaller than your original Shape
  2. Create a Shape circle that is a couple of pixels larger than your original Shape
  3. Create an Area object using the larger Shape
  4. Create an Area object using the smaller Shape and subtract this Area from the larger Area
  5. Use the contains(...) method to determine if the mouse point is within this Area.
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!