通过单击并拖动其外边缘来调整Path2D圆的大小

因此,当我在JPanel上单击并拖动Path2D圈时,它正在resize。 问题是,当我最初点击并拖动它时,圆圈跳转到较小的尺寸,但随后单击并拖动时正确resize。 最简单的演示方法是运行下面的可运行代码。

我知道我需要修复此代码:

@Override public void mouseDragged(MouseEvent e) { int mouseX = e.getX(); int mouseY = e.getY(); if (resizing) { System.out.println("resizing"); Rectangle bounds = shapes.get(currentIndex).getBounds(); int shapeX = bounds.x; int shapeY = bounds.y; shapes.get(currentIndex).reset(); shapes.get(currentIndex).append( new Ellipse2D.Double(shapeX, shapeY, mouseX - shapeX, mouseX - shapeX), true); repaint(); } } 

不过我不知道怎么回事 。 我点击圆的外边缘,然后我将圆的边界的长度和宽度设置为新鼠标点的位置……但我需要做的是圆的外边缘坐标到新的鼠标点。 关于如何计算正确点的任何想法?

完整代码

 import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; 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); } } 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 { Boolean hovering = false; Boolean resizing = true; @Override public void mouseMoved(MouseEvent e) { mousePoint = e.getPoint(); for (int i = 0; i < shapes.size(); i++) { Path2D shape = shapes.get(i); Rectangle2D bottomRight = getActiveBounds(-45, shape.getBounds()); if (mousePoint != null) { if (bottomRight.contains(mousePoint)) { Cursor cursor = Cursor .getPredefinedCursor(Cursor.SE_RESIZE_CURSOR); setCursor(cursor); hovering = true; } else { Cursor cursor = Cursor .getPredefinedCursor(Cursor.DEFAULT_CURSOR); setCursor(cursor); hovering = false; } } } repaint(); } @Override public void mousePressed(MouseEvent e) { if (hovering) { resizing = true; System.out.println("Starting to resize"); } } @Override public void mouseDragged(MouseEvent e) { int mouseX = e.getX(); int mouseY = e.getY(); if (resizing) { System.out.println("resizing"); Rectangle bounds = shapes.get(currentIndex).getBounds(); int shapeX = bounds.x; int shapeY = bounds.y; shapes.get(currentIndex).reset(); shapes.get(currentIndex).append( new Ellipse2D.Double(shapeX, shapeY, mouseX - shapeX, mouseX - shapeX), true); repaint(); } } @Override public void mouseReleased(MouseEvent e) { if (resizing) { System.out.println("Done resizing"); resizing = false; } } } } } 

你需要知道两件事,你需要知道按下鼠标的原始点和形状的原始边界

 private Point clickPoint; private Rectangle originalBounds; //... @Override public void mousePressed(MouseEvent e) { if (hovering) { resizing = true; System.out.println("Starting to resize"); clickPoint = e.getPoint(); originalBounds = new Rectangle(shapes.get(currentIndex).getBounds()); } } 

使用此信息,您可以计算原始点击点和拖动点之间的差值,使用此信息,您可以通过将差异添加到originalBounse来修改形状

 @Override public void mouseDragged(MouseEvent e) { if (resizing && clickPoint != null) { int mouseX = e.getX(); int mouseY = e.getY(); int xDelta = mouseX - clickPoint.x; int yDelta = mouseY - clickPoint.y; int delta = Math.max(xDelta, yDelta); Rectangle bounds = shapes.get(currentIndex).getBounds(); int shapeX = bounds.x; int shapeY = bounds.y; int shapeWidth = originalBounds.width + delta; int shapeHeight = originalBounds.height + delta; if (shapeWidth < 0) { shapeWidth *= -1; shapeX = originalBounds.x - shapeWidth; } if (shapeHeight < 0) { shapeHeight *= -1; shapeY = originalBounds.y - shapeHeight; } System.out.printf("%d %dx%dx%dx%d%n", delta, shapeX, shapeY, shapeWidth, shapeHeight); shapes.get(currentIndex).reset(); shapes.get(currentIndex).append( new Ellipse2D.Double(shapeX, shapeY, shapeWidth, shapeHeight), true); repaint(); } } 

当用户释放按钮时,别忘了重置clickPointoriginalBounds ;)

调整

 import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; 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); } } 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 { Boolean hovering = false; Boolean resizing = true; private Point clickPoint; private Rectangle originalBounds; @Override public void mouseMoved(MouseEvent e) { mousePoint = e.getPoint(); for (int i = 0; i < shapes.size(); i++) { Path2D shape = shapes.get(i); Rectangle2D bottomRight = getActiveBounds(-45, shape.getBounds()); if (mousePoint != null) { if (bottomRight.contains(mousePoint)) { Cursor cursor = Cursor .getPredefinedCursor(Cursor.SE_RESIZE_CURSOR); setCursor(cursor); hovering = true; } else { Cursor cursor = Cursor .getPredefinedCursor(Cursor.DEFAULT_CURSOR); setCursor(cursor); hovering = false; } } } repaint(); } @Override public void mousePressed(MouseEvent e) { if (hovering) { resizing = true; System.out.println("Starting to resize"); clickPoint = e.getPoint(); originalBounds = new Rectangle(shapes.get(currentIndex).getBounds()); } } @Override public void mouseDragged(MouseEvent e) { if (resizing && clickPoint != null) { int mouseX = e.getX(); int mouseY = e.getY(); int xDelta = mouseX - clickPoint.x; int yDelta = mouseY - clickPoint.y; int delta = Math.max(xDelta, yDelta); Rectangle bounds = shapes.get(currentIndex).getBounds(); int shapeX = bounds.x; int shapeY = bounds.y; int shapeWidth = originalBounds.width + delta; int shapeHeight = originalBounds.height + delta; if (shapeWidth < 0) { shapeWidth *= -1; shapeX = originalBounds.x - shapeWidth; } if (shapeHeight < 0) { shapeHeight *= -1; shapeY = originalBounds.y - shapeHeight; } System.out.printf("%d %dx%dx%dx%d%n", delta, shapeX, shapeY, shapeWidth, shapeHeight); shapes.get(currentIndex).reset(); shapes.get(currentIndex).append( new Ellipse2D.Double(shapeX, shapeY, shapeWidth, shapeHeight), true); repaint(); } } @Override public void mouseReleased(MouseEvent e) { if (resizing) { System.out.println("Done resizing"); resizing = false; clickPoint = null; originalBounds = null; } } } } }