Inspired by this question JLayeredPane with a LayoutManager I'm trying to get the JLayeredPane to work with the GridBagLayout.
Here's the custom LayeredPane-class:
class StackConstraints {
public final int layer;
public final Object layoutConstraints;
public StackConstraints(int layer, Object layoutConstraints) {
this.layer = layer;
this.layoutConstraints = layoutConstraints;
}
}
class LXLayeredPane extends JLayeredPane {
private static final long serialVersionUID = 1946283565823567689L;
@Override
protected void addImpl(Component comp, Object constraints, int index) {
int layer = 0;
int pos = 0;
Object constr = null;
if (constraints instanceof StackConstraints) {
layer = ((StackConstraints) constraints).layer;
constr = ((StackConstraints) constraints).layoutConstraints;
} else {
layer = getLayer(comp);
constr = constraints;
}
pos = insertIndexForLayer(layer, index);
super.addImpl(comp, constr, pos);
setLayer(comp, layer, pos);
comp.validate();
comp.repaint();
}
}
And here's a simple demo (similar to the standard-JLayeredPane demo but adapted for the usage of GridBagConstraints and stripped of the unnecessary stuff).
public class LayeredPaneDemo extends JPanel implements ActionListener {
private final Color[] layerColors = { Color.yellow, Color.magenta, Color.cyan, Color.red, Color.green, Color.blue };
private final JLayeredPane layeredPane;
private final List<JLabel> labels;
private JButton update;
public LayeredPaneDemo() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
labels = new ArrayList<>();
layeredPane = new LXLayeredPane();
layeredPane.setPreferredSize(new Dimension(400, 410));
layeredPane.setBorder(BorderFactory.createTitledBorder("Click to change colors"));
// Add several labels to the layered pane.
layeredPane.setLayout(new GridBagLayout());
for (int i = 0; i < layerColors.length; i++) {
JLabel label = createColoredLabel("Test", layerColors[i]);
labels.add(label);
layeredPane.add(label, new StackConstraints(i, gbc(i)));
}
// Add control pane and layered pane to this JPanel.
add(Box.createRigidArea(new Dimension(0, 10)));
add(createControlPanel());
add(Box.createRigidArea(new Dimension(0, 10)));
add(layeredPane);
}
private GridBagConstraints gbc(int i) {
return new GridBagConstraints(i, i, 2, 2, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0);
}
// Create and set up a colored label.
private JLabel createColoredLabel(String text, Color color) {
JLabel label = new JLabel(text);
label.setVerticalAlignment(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setOpaque(true);
label.setBackground(color);
label.setForeground(Color.black);
label.setBorder(BorderFactory.createLineBorder(Color.black));
label.setPreferredSize(new Dimension(240, 240));
return label;
}
// Create the control pane for the top of the frame.
private JPanel createControlPanel() {
update = new JButton("Update");
update.addActionListener(this);
update.setActionCommand("UPDATE");
JPanel controls = new JPanel();
controls.add(update);
controls.setBorder(BorderFactory.createTitledBorder("Choose Duke's Layer and Position"));
return controls;
}
@Override
public void actionPerformed(ActionEvent e) {
Color prev = labels.get(labels.size() - 1).getBackground();
for (int i = labels.size() - 1; i > 0; --i) {
labels.get(i).setBackground(labels.get(i - 1).getBackground());
labels.get(i).validate();
labels.get(i).repaint();
}
labels.get(0).setBackground(prev);
labels.get(0).validate();
labels.get(0).repaint();
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("LayeredPaneDemo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new LayeredPaneDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}
}
My problem is that I'm adding 6 (six!) labels but only 5 (five!) are displayed. The 0-th one just vanishes somewhere. What's the reason for that?
EDIT: The initial motivation behind the pursuit is to place one (partially transparent) component on top of another like in this screenshot The label displaying 17:00:09 has transparent background and is placed on top of the chart-component. GridBagLayout is needed to place it exactly at the top middle of the chart.
That is my point. I don't believe you need to customize JLayeredPane.
A layered pane is used to layer panels.
Then each individual panel can have its own layout manager whether it be GridBagLayout, FlowLayout or whatever.
For example, try updating the loop that creates the labels in the
LayeredPaneDemo
:The above code will just add a checkbox to the label using the default constraints which means the checkbox will be centered within the label.
I am not aware of any reason you can't use a different layout manager on each panel in the layered pane. If the layout isn't what you expect, then I would guess your
GridBagConstrainsts
are not correct.JLayeredPane
is irrelevant.