Draw Connecting Lines Between Swing Components
Hi all,
I'm writing a program to export data from one database to another one and I would like to provide a gui such as.:
- - - - - - - - - -- - - - - - - - - -
| column_01 | - - - - - - - | dest_01 |
- - - - - - - - - -- - - - - - - - - -
| column_02 || dest_02 |
- - - - - - - - - -- - - - - - - - - -
Could someone point me on how to resolve questions below ?
Q1. How can I write a line connecting two swing components ?
Q2. These swing components are inside of a scrolled component, How to keep track of the lines position ?
Thank you very much
Marcos
How can I write a line connecting two swing components ?
One way is to draw the line on the parent container.
These swing components are inside of a scrolled component, How to keep track of the lines position ?
Let the components keep track of things.
import java.awt.*;
import java.awt.geom.*;
import java.text.NumberFormat;
import javax.swing.*;
public class ConnectingLine
{
NumberFormat nf;
public ConnectingLine()
{
nf = NumberFormat.getInstance();
nf.setMinimumIntegerDigits(2);
}
private JPanel getContent()
{
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(20,0,20,0);
gbc.weightx = 1.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
for(int j = 0, k = 1; j < 5; j++, k+=2)
panel.add(getPanel(k), gbc);
return panel;
}
private JPanel getPanel(int n)
{
ConnectingPanel panel = new ConnectingPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5,5,5,5);
gbc.weightx = 1.0;
panel.add(getChild("column_", n), gbc);
panel.add(getChild("dest_", n), gbc);
return panel;
}
private JPanel getChild(String s, int n)
{
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridwidth = GridBagConstraints.REMAINDER;
panel.setOpaque(false); // no tricks
panel.setPreferredSize(new Dimension(125, 75));
panel.setBorder(BorderFactory.createEtchedBorder());
panel.add(new JLabel(s + nf.format(n), JLabel.CENTER), gbc);
gbc.weighty = 0.0;
panel.add(new JSeparator(), gbc);
gbc.weighty = 1.0;
panel.add(new JLabel(s + nf.format(n+1), JLabel.CENTER), gbc);
return panel;
}
public static void main(String[] args)
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new JScrollPane(new ConnectingLine().getContent()));
f.setSize(500,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
class ConnectingPanel extends JPanel
{
final int HI = 0;// top JLabel
// JSeparator is middle component
final int LO = 2;// bottom JLabel
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.blue);
Component[] c = getComponents();
for(int j = 0; j < c.length; j++)
{
for(int k = j+1; k < c.length; k++)
{
Point p1 = //getPointForParent(c[j], c[k]);
getPointForChild(c[j], c[k], HI);
Point p2 = //getPointForParent(c[k], c[j]);
getPointForChild(c[k], c[j], HI);
g2.draw(new Line2D.Double(p1, p2));
}
}
}
/** middle of parent JPanel that contains the two JLabels */
private Point getPointForParent(Component c1, Component c2)
{
Rectangle r1 = c1.getBounds();
Rectangle r2 = c2.getBounds();
Point p = new Point();
int outcode = r1.outcode(r2.getCenterX(), r2.getCenterY());
switch(outcode)
{
case Rectangle2D.OUT_TOP:
break;
case Rectangle2D.OUT_LEFT:
p.x = r1.x;
p.y = r1.y + r1.height/2 -1;
break;
case Rectangle2D.OUT_BOTTOM:
break;
case Rectangle2D.OUT_RIGHT:
p.x = r1.x + r1.width -1;
p.y = r1.y + r1.height/2 -1;
break;
default:
System.out.println("outcode for center or corners " + outcode);
}
return p;
}
/** center of top (or bottom) JLabel - as shown in ascii art above */
private Point getPointForChild(Component c1, Component c2, int index)
{
Rectangle r1 = c1.getBounds();
Point cp = getCenter(c1, index);
Rectangle r2 = c2.getBounds();
Point p = new Point();
int outcode = r1.outcode(r2.getCenterX(), r2.getCenterY());
switch(outcode)
{
case Rectangle2D.OUT_TOP:
break;
case Rectangle2D.OUT_LEFT:
p.x = r1.x;
p.y = cp.y;
break;
case Rectangle2D.OUT_BOTTOM:
break;
case Rectangle2D.OUT_RIGHT:
p.x = r1.x + r1.width -1;
p.y = cp.y;
break;
default:
System.out.println("outcode for center or corners " + outcode);
}
return p;
}
private Point getCenter(Component parent, int childIndex)
{
Component child = ((Container)parent).getComponent(childIndex);
Rectangle r = child.getBounds();
Rectangle parentBounds = parent.getBounds();
Point p = new Point();
p.x = parentBounds.width/2;
p.y = parentBounds.y + r.y + r.height/2;
return p;
}
}