拖动以在JPanel中移动Line2D

时间:2014-10-22 17:32:04

标签: java swing drag shapes

所以,我试图点击并拖动一条线。我几乎在那里,但我认为我有一个问题,计算线在用户拖动的位置。当我点击并拖动时, 移动,就像我想的那样。我想我的代码有问题:

       @Override
        public void mouseDragged(MouseEvent e) {
            Point p = e.getPoint();
            if (resizing) {
                endPoint.x = p.x;
                endPoint.y = p.y;
                double offsetX = endPoint.x - startPoint.x;
                double offsetY = endPoint.y - startPoint.y;
                int newX1 = (int)(lines.get(currentIndex).getX1() - offsetX);
                int newX2 = (int)(lines.get(currentIndex).getX2() - offsetX);
                int newY1 = (int)(lines.get(currentIndex).getY1() - offsetY);
                int newY2 = (int)(lines.get(currentIndex).getY2() - offsetY);

                lines.get(currentIndex).setLine(newX1, newY1, newX2, newY2);

                repaint();
            }
        }

关于如何让它发挥作用的任何想法?

MCVE

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.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
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 UMLWindow2();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setBounds(30, 30, 1000, 700);
                frame.getContentPane().setBackground(Color.white);
                frame.setVisible(true);
                frame.setLocationRelativeTo(null);
            }
        });
    }

    public static class UMLWindow2 extends JFrame {

        Shapes shapeList = new Shapes();
        Panel panel;

        private static final long serialVersionUID = 1L;

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

        public void addMenus() {

            getContentPane().add(shapeList);

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

            shapeList.addLine();
        }
    }

    // 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<Line2D.Double> lines = new ArrayList<Line2D.Double>();
        private Line2D.Double linePath;

        double phi = Math.toRadians(40);
        int barb = 20;

        Boolean hovering = false;
        Boolean resizing = false;

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

        public void addLine() {
            linePath = new Line2D.Double(300, 300, 500, 500);
            lines.add(linePath);
            repaint();
        }

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

            Graphics2D g2 = (Graphics2D) g;
            g2.setStroke(new BasicStroke(2));
            for (Line2D line : lines) {
                g2.setColor(Color.BLACK);
                Point sw = new Point((int) line.getX1(), (int) line.getY1());
                Point ne = new Point((int) line.getX2(), (int) line.getY2());
                g2.draw(line);
                drawArrowHead(g2, ne, sw, Color.BLACK);
            }
        }

        private void drawArrowHead(Graphics2D g2, Point tip, Point tail,
                Color color) {
            g2.setPaint(color);
            double dy = tip.y - tail.y;
            double dx = tip.x - tail.x;
            double theta = Math.atan2(dy, dx);
            double x, y, rho = theta + phi;
            for (int j = 0; j < 2; j++) {
                x = tip.x - barb * Math.cos(rho);
                y = tip.y - barb * Math.sin(rho);
                g2.draw(new Line2D.Double(tip.x, tip.y, x, y));
                rho = theta - phi;
            }
        }

        class MyMouseAdapter extends MouseAdapter {
            int currentIndex;
            Point2D.Double startPoint = new Point2D.Double();
            Point2D.Double endPoint = new Point2D.Double();

            @Override
            public void mousePressed(MouseEvent e) {
                Point p = e.getPoint();
                if (hovering) {
                    System.out.println("Starting to resize");
                    startPoint.x = p.x;
                    startPoint.y = p.y;
                    resizing = true;
                }
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                Point p = e.getPoint();
                if (resizing) {
                    endPoint.x = p.x;
                    endPoint.y = p.y;
                    double offsetX = endPoint.x - startPoint.x;
                    double offsetY = endPoint.y - startPoint.y;
                    System.out.println("Point 1: "
                            + lines.get(currentIndex).getX1() + ", "
                            + lines.get(currentIndex).getY1() + " Point 2: "
                            + lines.get(currentIndex).getX2() + ", "
                            + lines.get(currentIndex).getY2());
                    int newX1 = (int) (lines.get(currentIndex).getX1() + offsetX);
                    int newX2 = (int) (lines.get(currentIndex).getX2() + offsetX);
                    int newY1 = (int) (lines.get(currentIndex).getY1() + offsetY);
                    int newY2 = (int) (lines.get(currentIndex).getY2() + offsetY);

                    lines.get(currentIndex).setLine(newX1, newY1, newX2, newY2);

                    repaint();
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if (resizing) {
                    System.out.println("Done resizing");
                    resizing = false;
                }
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                Point p = e.getPoint();
                Rectangle2D.Double rect = new Rectangle2D.Double(p.x - 1,
                        p.y - 1, 3, 3);
                for (int i = 0; i < lines.size(); i++) {
                    Line2D line = lines.get(i);
                    if (line.intersects(rect)) {
                        setCursor(new Cursor(Cursor.HAND_CURSOR));
                        currentIndex = i;
                        hovering = true;
                    } else {
                        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                        hovering = false;
                    }
                }
            }

        }

    }
}

1 个答案:

答案 0 :(得分:2)

我不知道这是否会有所帮助或混淆,但拖动的一种方法是创建一个能够拖动任何组件的自定义类。下一个问题是能够创建不同形状的组件。

您可以先查看:

  1. Playing With Shapes。此类允许您创建任何Shape的自定义组件。组件将尊重Shape的实际边界(不是矩形边界),因此处理鼠标事件很容易。

  2. Component Mover。此类允许您通过使用ComponentMover注册组件来拖动组件。

  3. 以下示例代码尝试演示这两个类。创建封闭的形状(圆形,正方形,星形)相对容易。创建箭头更难。我尝试了两种不同的方式。

    第一个是使用GeneralPath。代码很简单,但Shape.contains(...)方法没有按预期工作,因为GeneralPath似乎关闭了起点/终点以创建一个三角形。这对于绘画是可以的,但不适合移动,因为点击三角形中的任何位置都会导致箭头移动。

    第二种尝试是通过创建两个略有不同大小的不同三角形来创建更复杂的形状,然后从较大的三角形中减去较小三角形的区域以留下箭头的轮廓。在这种情况下,Shape.contains(..)方法按预期工作,因此拖动也可以按预期工作。

    享受代码:

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import javax.swing.*;
    import javax.swing.border.*;
    
    public class ShapeComponentTest
    {
        private static void createAndShowUI()
        {
            Border line = new LineBorder(Color.BLUE, 5);
    
            Polygon outer = new Polygon();
            outer.addPoint(0, 50);
            outer.addPoint(50, 25);
            outer.addPoint(0, 0);
            Polygon inner = new Polygon();
            inner.addPoint(0, 45);
            inner.addPoint(43, 25);
            inner.addPoint(0, 5);
    
            Area arrow = new Area(outer);
            arrow.subtract(new Area(inner));
    
            GeneralPath part1 = new GeneralPath();
            part1.moveTo(0, 50);
            part1.lineTo(50, 25);
            part1.lineTo(0, 0);
    
            ShapeComponent ball = new ShapeComponent( arrow ); // drags correctly
    //      OutlineComponent ball = new OutlineComponent( part1, 3 ); // drags incorrectly
            ball.setForeground(Color.ORANGE);
            ball.setBorder( line );
            ball.setSize( ball.getPreferredSize() );
    
            OutlineComponent square = new OutlineComponent( new Rectangle(30, 30) );
            square.setForeground(Color.ORANGE);
            square.setLocation(50, 50);
            square.setBorder(line);
            square.setSize( square.getPreferredSize() );
    
            OutlineComponent star = new OutlineComponent( ShapeUtils.radiusShape(16, 20, 8) );
    
            star.setForeground(Color.ORANGE);
            star.setLocation(100, 100);
            star.setBorder(line);
            star.setSize( star.getPreferredSize() );
    
            ComponentMover cm = new ComponentMover();
            cm.registerComponent(star);
            cm.registerComponent(ball);
            cm.registerComponent(square);
    
            JPanel panel = new JPanel();
            panel.setLayout(null);
            panel.add(ball);
            panel.add(square);
            panel.add(star);
    
            JFrame frame = new JFrame(); frame.add(panel);
            frame.setSize(200, 200); frame.setVisible(true);
    
            MouseListener ml = new MouseAdapter()
            {
                public void mouseClicked( MouseEvent e )
                {
                    System.out.println( "clicked " );
                }
            };
    
            ball.addMouseListener( ml );
            square.addMouseListener( ml );
            star.addMouseListener( ml );
        }
    
        public static void main(String[] args)
        {
            EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    createAndShowUI();
                }
            });
        }
    }