使用鼠标来增长/销毁表示对象之间连接的线条

时间:2014-08-31 16:31:43

标签: java swing

我正在编写一个包含端口对象和目标对象的实用程序。我希望它具有以下特征:

  • 可以动态创建端口图标,然后链接到任何或所有现有目标图标。
  • 用户按住Shift键点击端口图标并拖动到目标图标以创建连接。
  • 当用户将鼠标从端口拖动到目标时,表示连接的线会增长并捕捉到位。
  • 右键单击连接线会断开端口与目标的连接。
  • 可以自由拖动端口和目标图标。
  • 可以销毁端口对象

Like this

我想使用Swing这样做,但我可以接受其他建议。

Here's an SO thread that gets me part of the way there in Swing

我的问题是

  • 如何成长'对齐的线
  • 如何使线条可点击

1 个答案:

答案 0 :(得分:2)

  

“如何使线条可点击”

你应该使用抽象。创建一个SelectableLine类,其中包含Line2DisSelected等属性。在MouseListener中获取Point中的MouseEvent。您可能希望从该点创建一个小矩形区域,这样您就不必完全单击该行。使用Rectangle查看行intersects()。如果是,setSelected上的SelectableRectangle。您可以选择使用isSelected行执行任何操作。在下面的示例中,我只是更改颜色以显示它已被选中。

这是一个例子(注意:有很多方法可以实现这一点。这只是我“在10分钟内把东西放在一起”版本)

enter image description here

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SelectLineDemo {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new SelectLineDemo();
            }
        });
    }

    public SelectLineDemo() {
        JFrame frame = new JFrame();
        frame.add(new SelectLinePanel());
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    class SelectableLine {
        boolean selected = false;
        Line2D line;

        public SelectableLine(Line2D line) {
            this.line = line;
        }

        public boolean intersects(Rectangle rectangle) {
            return line.intersects(rectangle);
        }

        public void setSelected(boolean selected) {
            this.selected = selected;
        }

        public boolean isSelected() {
            return selected;
        }

        public Line2D getLine() {
            return line;
        }
    }

    class SelectLinePanel extends JPanel {
        private int selectionRadius = 5;
        private final Color SELECTED_COLOR = Color.BLUE;
        private final Color UNSELECTED_COLOR = Color.BLACK;
        private final Stroke STROKE = new BasicStroke(5.0f);

        private List<SelectableLine> lines = new ArrayList<SelectableLine>();

        public SelectLinePanel() {
            initLines();

            addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent e) {
                    Point p = e.getPoint();
                    Rectangle selectionRect = getRectangleFromPoint(p);
                    checkIfLinesAreSelected(selectionRect);
                    repaint();
                }
            });
        }

        private void checkIfLinesAreSelected(Rectangle rectangle) {
            for (SelectableLine line : lines) {
                if (line.intersects(rectangle)) {
                    line.setSelected(true);
                } else {
                    line.setSelected(false);
                }
            }
        }

        private Rectangle getRectangleFromPoint(Point p) {
            int x = p.x - selectionRadius;
            int y = p.y - selectionRadius;
            int size = selectionRadius * 2;
            Rectangle selectionRect = new Rectangle(x, y, size, size);
            return selectionRect;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setStroke(STROKE);
            for (SelectableLine line : lines) {
                if (line.isSelected()) {
                    g2d.setColor(SELECTED_COLOR);
                } else {
                    g2d.setColor(UNSELECTED_COLOR);
                }
                g2d.draw(line.getLine());
            }
        }

        private void initLines() {
            for (int i = 50; i <= 350; i += 50) {
                lines.add(new SelectableLine(new Line2D.Double(50, i, 350, i)));
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }
}

  

“如何让'成长'线条突然出现”

另一方面,这不是一项微不足道的任务(即我不能在十分钟内完成任务)。您可能希望在行尾创建某种锚点。也许在每个终点添加一个小Rectangle。拖动矩形时,该行将跟随它。对于捕捉矩形,您需要一个算法来确定要将其锚定到的形状边缘的最近点。松开鼠标时,将其卡入到位。


您可能想要查看一些编码想法的资源。

参见Dr.John.B.Matthews的GraphPanel(从this SO answer获得的链接)

GraphPanel image

请参阅Move an Oval in java

中@MadProgrammer的回答

MadProgrammer1