【问题标题】:How can we Draw a lines between 2 panels in swing我们如何在摆动的两个面板之间画一条线
【发布时间】:2012-09-05 02:52:26
【问题描述】:

只想通过在面板上画一条线来连接面板。

我有两个面板,两个面板都包含一个 Jtable。我想将一个面板的 jtable 的每个单元格连接到另一个 jpanel 的另一个 Jtable。

在这里我想画出我用粉红色圆圈突出显示的线条。

这是我用来创建 jtables 的代码 sn-p

 DefaultTableModel fcdbDataModel = new DefaultTableModel(fcdbIdTxnArray,
    fcdbIdTxnColumnArray);
fcdbIdTxnJTable = new FieldMapperJTable(fcdbDataModel);

这里的 FieldMapperJTable 是我自定义的 jtable 类。

【问题讨论】:

  • 任何类型的帮助或使用其他方式的想法将不胜感激。提前非常感谢。
  • @Stanislav 非常感谢您的帖子。这对我有用。 "java-sl.com/connector.html"
  • @Will 想知道你为什么删除了 Stani 的答案——这绝对有帮助
  • @kleopatra 那个帖子真的很棒,而且知识渊博。
  • 重复链接(您的副本包含最后一个引号,所以给出 404)@​​987654322@@Stanislav

标签: java swing user-interface graphics jtable


【解决方案1】:

您可以使用 JFrame/JDialog GlassPane 作为绘画字段轻松做到这一点。只需将您的自定义组件设置为框架的玻璃窗格,然后直接在其上绘制链接。

您也可以使用框架/对话框的分层窗格来执行相同操作。

这是一个关于如何在玻璃窗格组件上绘制此类“链接”的小型工作示例:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

/**
 * @see http://stackoverflow.com/a/12389479/909085
 */

public class ComponentLinkerTest extends JComponent
{
    private Map<JComponent, JComponent> linked;

    public ComponentLinkerTest ()
    {
        super ();
        linked = new HashMap<JComponent, JComponent> ();
    }

    public void link ( JComponent c1, JComponent c2 )
    {
        linked.put ( c1, c2 );
        repaint ();
    }

    protected void paintComponent ( Graphics g )
    {
        Graphics2D g2d = ( Graphics2D ) g;
        g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );

        g2d.setPaint ( Color.BLACK );
        for ( JComponent c1 : linked.keySet () )
        {
            Point p1 = getRectCenter ( getBoundsInWindow ( c1 ) );
            Point p2 = getRectCenter ( getBoundsInWindow ( linked.get ( c1 ) ) );
            g2d.drawLine ( p1.x, p1.y, p2.x, p2.y );
        }
    }

    private Point getRectCenter ( Rectangle rect )
    {
        return new Point ( rect.x + rect.width / 2, rect.y + rect.height / 2 );
    }

    private Rectangle getBoundsInWindow ( Component component )
    {
        return getRelativeBounds ( component, getRootPaneAncestor ( component ) );
    }

    private Rectangle getRelativeBounds ( Component component, Component relativeTo )
    {
        return new Rectangle ( getRelativeLocation ( component, relativeTo ),
                component.getSize () );
    }

    private Point getRelativeLocation ( Component component, Component relativeTo )
    {
        Point los = component.getLocationOnScreen ();
        Point rt = relativeTo.getLocationOnScreen ();
        return new Point ( los.x - rt.x, los.y - rt.y );
    }

    private JRootPane getRootPaneAncestor ( Component c )
    {
        for ( Container p = c.getParent (); p != null; p = p.getParent () )
        {
            if ( p instanceof JRootPane )
            {
                return ( JRootPane ) p;
            }
        }
        return null;
    }

    public boolean contains ( int x, int y )
    {
        return false;
    }

    private static ComponentLinkerTest linker;

    public static void main ( String[] args )
    {
        setupLookAndFeel ();

        JFrame frame = new JFrame ();

        linker = new ComponentLinkerTest ();
        frame.setGlassPane ( linker );
        linker.setVisible ( true );

        JPanel content = new JPanel ();
        content.setLayout ( new GridLayout ( 10, 5, 5, 5 ) );
        content.setBorder ( BorderFactory.createEmptyBorder ( 5, 5, 5, 5 ) );
        frame.add ( content );

        for ( int i = 0; i < 50; i++ )
        {
            final JButton button = new JButton ( "Button" + i );
            button.addActionListener ( new ActionListener ()
            {
                public void actionPerformed ( ActionEvent e )
                {
                    link ( button );
                }
            } );
            content.add ( button );
        }

        frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
        frame.pack ();
        frame.setLocationRelativeTo ( null );
        frame.setVisible ( true );
    }

    private static JButton last = null;

    private static void link ( JButton button )
    {
        if ( last == null )
        {
            last = button;
        }
        else
        {
            linker.link ( last, button );
            last = null;
        }
    }

    private static void setupLookAndFeel ()
    {
        try
        {
            UIManager.setLookAndFeel ( UIManager.getSystemLookAndFeelClassName () );
        }
        catch ( ClassNotFoundException e )
        {
            e.printStackTrace ();
        }
        catch ( InstantiationException e )
        {
            e.printStackTrace ();
        }
        catch ( IllegalAccessException e )
        {
            e.printStackTrace ();
        }
        catch ( UnsupportedLookAndFeelException e )
        {
            e.printStackTrace ();
        }
    }
}

结果:
(只需依次单击任意两个按钮即可链接)

附:为了使线条更粗,您可以在绘画时更改笔触:

g2d.setStroke ( new BasicStroke ( 5f ) );

【讨论】:

  • 我不确定这是否仍然适用,但在 Swing 是新的和闪亮的日子里,我在尝试使用玻璃窗格时遇到了很多处理事件的问题。
  • +1 用于渲染组件,以及令人钦佩的评论风格。 :-)
  • @JensSchauder 是的,有问题,如果你想让玻璃板处理任何事件(不是问题,但实际上是小困难)。无论如何,这就是为什么我覆盖玻璃窗格组件的“包含”方法。如果你总是在那里返回 false (或用线条的形状限制它) - 它不会在任何地方“吸收”事件(或者只是在形状边界内,这也很好)。
  • @trashgod 谢谢,总是尽可能地改进代码和 cmets :)
  • 重复我对已删除答案的评论:@Sunil 如果您在 jdk7 上,您可能会考虑获取 Stan 的逻辑并在 JLayer/UI 中实现它。与此类似:糟糕的 ol' GlassPane 很难正确处理(多年来没有变化)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多