【问题标题】:Resizing Path2D circle by clicking and dragging its outer edge通过单击并拖动其外边缘来调整 Path2D 圆的大小
【发布时间】:2014-10-20 23:34:10
【问题描述】:

所以,当我在 JPanel 上单击并拖动一个 Path2D 圆圈时,它正在调整大小。问题是,当我最初单击并拖动它时,圆圈会跳转到较小的尺寸,但随后会在您单击并拖动时正确调整大小。最简单的演示方法是运行下面的可运行代码。

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

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

不过,我不确定如何。我单击圆的外边缘,然后将圆的边界的 length 和 width 设置为新鼠标点的位置......但我需要做的是圆的坐标的外边缘到新的鼠标点。关于如何计算正确点的任何想法?

完整代码

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

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

        }
    }

}

【问题讨论】:

  • 你需要知道鼠标按下的位置和拖到的位置的区别...
  • 是的,但是从外边缘到边界角的距离会随着圆圈大小的变化而变化,对吧?很难理解这个
  • 您想知道的是您开始的位置和现在的位置之间的变化增量(差异)。圆圈的位置不会改变,只是它的大小
  • 是的,但我将我现在所在的位置设置为围绕它的圆圈的边界,而不是圆圈现在所在的位置
  • 所以,获取形状原始边界的副本;)

标签: java swing jpanel shapes


【解决方案1】:

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

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

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

        }
    }

}

【讨论】:

  • 感谢您的代码,但更重要的是感谢您的描述。我无法弄清楚如何计算新圆的长度。欣赏!
  • 是的,我只是使用最大增量来保持循环,但您也可以使用最小增量,这取决于您追求的效果;)
  • 是的,我相信这样会更好。再次感谢。我相信我很快就会再见到你;)
猜你喜欢
  • 2012-01-17
  • 1970-01-01
  • 2011-12-07
  • 2020-10-19
  • 2017-08-30
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
相关资源
最近更新 更多