感知hover在JPanel中的Path2D圆的外边缘

所以,我有一个程序将Path2D圈子绘制到JPanel上。 我想要做的是在用户点击并拖动圆圈的右下角时调整圆圈的大小。 所以,我想要的是检测它们何时位于圆的右下边缘,而不是圆周边界的右下角 。 基本上,我需要弄清楚如何做这样的事情:

在此处输入图像描述

我知道如何使用getBounds()对矩形执行此操作,但是当您在圆上使用getBounds()时,它将返回围绕圆的方形而不是实际圆的边界。 关于如何让它发挥作用的任何想法? 谢谢!

这是我的程序的缩短的,可运行的版本:

import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Panel; 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.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; public class Editor { public static void main(String[] args) { 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); } } 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 class Shapes extends JPanel { private static final long serialVersionUID = 1L; private List shapes = new ArrayList(); int currentIndex; 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.draw(shape); } } class MyMouseAdapter extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } } } 

你会想要刷新你的触发(或谷歌搜索,就像我做的那样;))。 基本概念“相对”容易,但我为我的所有工作创造了一个很好的方法……

这个方法……

 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); } 

将计算给定角度将出现在圆圈上的x / y点,请记住,这仅适用于圆圈!

然后我用另一种方法……

 public Rectangle2D getActiveBounds(float angel, Rectangle bounds) { Point2D p = getPointOnEdge(angel, bounds); return new Rectangle2D.Double(p.getX() - 4, p.getY() - 4, 8, 8); } 

要计算我认为是底部/右侧区域的“鼠标区域”,导致难以找到单个像素,只需使用Rectangle#contains ,将其传递给当前鼠标位置……

鼠标悬停

 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 shapes = new ArrayList(); 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(); } } } } 

这个例子完成了paint方法中的所有工作,因为我想看到“效果区域”,你可以轻松地使用相同的逻辑来改变MouseMoitionListener的鼠标光标

不确定这是否有效,但您可以尝试以下方法:

  1. 创建一个比原始Shape小几个像素的Shape圆
  2. 创建一个比原始Shape大几个像素的Shape圆
  3. 使用较大的Shape创建Area对象
  4. 使用较小的Shape创建Area对象,并从较大的Area中减去此Area
  5. 使用contains(…)方法确定鼠标点是否在此区域内。