在按钮摆动之间绘制可点击线

Foo*_*ble 1 java swing

我有一个以特定图案布置的物体网格.单击对象将触发某些操作,例如显示有关该对象的信息或导航到另一个屏幕.

每个对象还具有与其他对象的连接.这些连接需要可点击,因为单击它们将显示有关该连接的更多信息.

以下示例显示了我的目标.网格中的每个蓝色圆圈都是可点击的对象,它们之间的每条红线都是可点击的连接.

例1

我已经尝试将对象和连接作为Jbuttons存储在单个网格包布局中,并且已经取得了一些成功,因为连接是可点击的.

但是,连接跨越单个方向的多个单元格,Jbuttons展开以填充布局单元格.这导致连接的末端穿过物体的中心并在网格袋单元的边界处完成.

这是我的意思:

例2

是否有一些更简单的方法来制作这种界面/以前有人这样做过吗?

Mad*_*mer 5

好的,非常基本,但想法是在对象之间手动绘制线条.

在这种情况下,我创建了一个Connection维护按钮之间关系的简单对象.我后来干脆使用paintComponent的方法JPanel绘制的实际线.

我会让你设计一个更好的路径生成方法;)

路径

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JButton[] buttons = new JButton[]{
            new JButton("1"),
            new JButton("2"),
            new JButton("3"),
            new JButton("4"),};

        private List<Connection> connections;

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(10, 10, 10, 10);
            add(buttons[0], gbc);

            gbc.gridx = 2;
            gbc.gridy = 0;
            add(buttons[1], gbc);

            gbc.gridx = 1;
            gbc.gridy = 1;
            add(buttons[2], gbc);

            gbc.gridx = 2;
            gbc.gridy = 2;
            add(buttons[3], gbc);

            connections = new ArrayList<Connection>(25);
            connections.add(new Connection(buttons[0], buttons[1]));
            connections.add(new Connection(buttons[0], buttons[2]));
            connections.add(new Connection(buttons[0], buttons[3]));

            connections.add(new Connection(buttons[1], buttons[3]));
            connections.add(new Connection(buttons[2], buttons[3]));
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            for (Connection connection : connections) {
                JButton source = connection.getSource();
                JButton dest = connection.getDestination();

                if (source.getX() == dest.getX()) {
                    // Same column...
                    g2d.drawLine(source.getX() + source.getWidth() / 2, source.getY(),
                                    dest.getX() + source.getWidth() / 2, dest.getY());
                } else if (source.getY() == dest.getY()) {
                    // Same row...
                    g2d.drawLine(source.getX(), source.getY() + source.getHeight() / 2,
                                    dest.getX(), dest.getY() + dest.getHeight() / 2);
                } else {

                    Path2D path = new Path2D.Double();
                    path.moveTo(horizontalCenter(source), verticalCenter(source));
                    path.curveTo(horizontalCenter(source), verticalCenter(dest), 
                                    horizontalCenter(source), verticalCenter(dest), 
                                    horizontalCenter(dest), verticalCenter(dest));
                    g2d.draw(path);

                }
            }
            g2d.dispose();
        }

        protected double horizontalCenter(JComponent bounds) {

            return bounds.getX() + bounds.getWidth() / 2d;

        }

        protected double verticalCenter(JComponent bounds) {

            return bounds.getY() + bounds.getHeight() / 2d;

        }

        protected boolean hasIntersection(Line2D line, JComponent... exclude) {
            List<JComponent> toExclude = Arrays.asList(exclude);
            boolean intersects = false;
            for (Component comp : getComponents()) {
                if (!toExclude.contains(comp)) {
                    if (line.intersects(comp.getBounds())) {
                        System.out.println(line.getP1() + "-" + line.getP2() + " intersets with " + ((JButton)comp).getText() + "; " + comp.getBounds());
                        intersects = true;
                        break;
                    }
                }
            }
            return intersects;
        }

        protected Line2D lineDownTo(JComponent from, JComponent to) {
            return new Line2D.Double(horizontalCenter(from), from.getY(), horizontalCenter(from), verticalCenter(to));      
        }

        protected Line2D lineAcrossTo(JComponent from, JComponent to) {
            return new Line2D.Double(from.getX(), verticalCenter(from), horizontalCenter(to), verticalCenter(from));        
        }

        protected Point2D centerOf(Rectangle bounds) {
            return new Point2D.Double(bounds.getX() + bounds.getWidth() / 2, bounds.getY() + bounds.getHeight() / 2);
        }

        protected boolean canGoDownTo(Point2D startPoint, Point2D endPoint, JComponent to, JComponent from) {
            Point2D targetPoint = new Point2D.Double(startPoint.getX(), endPoint.getY());
            return !hasIntersection(new Line2D.Double(startPoint, targetPoint), to, from);
        }

        public class Connection {

            private final JButton source;
            private final JButton destination;

            public Connection(JButton source, JButton destination) {
                this.source = source;
                this.destination = destination;
            }

            public JButton getSource() {
                return source;
            }

            public JButton getDestination() {
                return destination;
            }

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 哦,对不起,忘记那一部分:P - 你可以(并且应该)缓存连接两个对象的`Path2D`,你应该能够使用`Path2D #content`来获得被点击的线的一般意义 (2认同)