问题
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.
回答1:
- As @camickr has already said,
JLayeredPane
is irrelevant. - Take a look at GridBagLayout to create a board | Oracle Community. May be it helps.
Darryl.Burke said:
A column (or row) in a GridBagLayout is not well defined unless there is at least one component which occupies only that column (or row). All your rows have components spanning 2 columns.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;
public class LayeredPaneDemo2 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 LayeredPaneDemo2() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
labels = new ArrayList<>();
// JLayeredPane is not much related, it is a problem of how to use GridBagLayout.
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" + i, layerColors[i]);
labels.add(label);
layeredPane.add(label, new StackConstraints(i, gbc(i)));
}
// //TEST1: Create reference grid
// GridBagConstraints c = new GridBagConstraints(
// 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,
// GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
// for (int i = 0; i < layerColors.length + 1; i++) {
// c.gridx = i;
// c.gridy = i;
// layeredPane.add(Box.createRigidArea(new Dimension(20, 20)), c);
// }
//TEST2: Create reference grid >>>
GridBagConstraints c = new GridBagConstraints(
6, 6, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
for (int i = 0; i < layerColors.length; i++) {
c.gridx = i;
Component box = Box.createRigidArea(new Dimension(20, 20));
((JComponent) box).setBorder(BorderFactory.createLineBorder(Color.RED));
layeredPane.add(box, c);
}
c.gridx = 6;
for (int i = 0; i < layerColors.length; i++) {
c.gridy = i;
Component box = Box.createRigidArea(new Dimension(20, 20));
((JComponent) box).setBorder(BorderFactory.createLineBorder(Color.RED));
layeredPane.add(box, c);
}
// <<<
// 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) {
@Override protected void paintComponent(Graphics g) {
g.setColor(new Color(100, 100, 100, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
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 LayeredPaneDemo2();
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();
}
});
}
}
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 {
@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();
}
}
回答2:
is there a fundamental reason why I cannot mix layers and GridBagLayout?
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
:
JLabel label = null;
for (int i = 0; i < layerStrings.length; i++) {
//JLabel label = createColoredLabel(layerStrings[i], layerColors[i], origin);
label = createColoredLabel(layerStrings[i], layerColors[i], origin);
layeredPane.add(label, new Integer(i));
origin.x += offset;
origin.y += offset;
}
label.setLayout( new GridBagLayout() );
label.add(new JCheckBox("Check Me"), new GridBagConstraints() );
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.
来源:https://stackoverflow.com/questions/42413590/jlayeredpane-and-gridbagconstraints