JLayeredPane和GridBagConstraints

时间:2017-02-23 10:49:29

标签: java swing layout-manager gridbaglayout jlayeredpane

受这个问题的启发 JLayeredPane with a LayoutManager 我正在尝试让JLayeredPane与GridBagLayout一起使用。

这是自定义的LayeredPane类:

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();
    }
}

这是一个简单的演示(类似于标准-JLayeredPane演示,但适用于GridBagConstraints的使用并剥离了不必要的东西)。

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();
            }
        });
    }

}

我的问题是我添加了6个(6个!)标签,但只显示了5个(5个!)。第0个就消失了。这是什么原因?

编辑:追求的最初动机是将一个(部分透明)组件放在另一个上面,就像在此屏幕截图中一样 enter image description here 显示17:00:09的标签具有透明背景,位于图表组件的顶部。需要使用GridBagLayout将其精确放置在图表的顶部中间位置。

2 个答案:

答案 0 :(得分:3)

  • 正如@camickr所说,JLayeredPane无关紧要。
  • 看看GridBagLayout to create a board | Oracle Community。可能有帮助。
      达里尔。伯克说:
      除非至少有一个组件仅占用该列(或行),否则GridBagLayout中的列(或行)定义不明确。您的所有行都包含2列的组件。

screenshot

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();
  }
}

答案 1 :(得分:1)

  

有一个根本原因,我不能混合图层和GridBagLayout?

这是我的观点。我不相信你需要自定义JLayeredPane。

分层窗格用于对面板进行分层。

然后,每个单独的面板都可以拥有自己的布局管理器,无论是GridBagLayout,FlowLayout还是其他。

例如,尝试更新在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() );

上面的代码只会使用默认约束为标签添加一个复选框,这意味着复选框将在标签中居中。

我不知道您在分层窗格中的每个面板上都不能使用不同的布局管理器。如果布局不符合您的预期,那么我猜您的GridBagConstrainsts不正确。