【问题标题】:JLayeredPane and GridBagConstraintsJLayeredPane 和 GridBagConstraints
【发布时间】:2017-07-13 19:21:57
【问题描述】:

受这个问题的启发 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 个(六个!)标签,但只显示了 5 个(五个!)。第 0 个就在某处消失了。这是什么原因?

编辑: 追求的最初动机是将一个(部分透明)组件放在另一个组件之上,就像这个屏幕截图一样 显示 17:00:09 的标签具有透明背景并放置在图表组件的顶部。需要 GridBagLayout 才能将其准确放置在图表的顶部中间。

【问题讨论】:

  • I'm trying to get the JLayeredPane to work with the GridBagLayout. - 为什么?这是两个不同的概念。分层窗格用于显示层中的组件。 GridBagLayout 用于在面板上显示组件。您要解决的确切问题是什么?我看不出您实现的行为与原始分层窗格演示的行为有何不同。
  • 编辑了答案以解释动机。我本可以为每个不同的图层使用具有透明背景的面板和 GridBagLayout,但它们只是不想正常工作。
  • but they just didn't want to work properly - 这并没有定义问题。您有两个潜在问题,1)分层窗格代码或 2)每个面板上用于 GridBagLayout 的约束。发布一个正确的minimal reproducible example 来证明问题。从图片中我无法判断堆叠的组件或实际问题是什么。
  • 亲爱的罗伯特,我可能在之前的评论中说错了。我发布的屏幕截图来自我最终通过使用多个面板开发的 GUI,每个面板都带有 GridBagLayout,因此已经达到了最初的目标。但是,在尝试通过扩展JLayeredPane 并使用它来解决问题时,我遇到了JLabels 的上述问题。我只是想了解这种特殊行为的原因:我的示例中是否有错误,或者是否存在我无法混合图层和GridBagLayout 的根本原因?
  • 它认为第一个标签与下一个标签被分配相同的位置(x,y),并且被认为完全被遮挡,因此不被绘制。因此错误出现在布局阶段,而不是在绘画过程中

标签: java swing layout-manager gridbaglayout jlayeredpane


【解决方案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 不正确。

【讨论】:

    【解决方案2】:
    • 正如@camickr 已经说过的,JLayeredPane 无关紧要。
    • 看看GridBagLayout to create a board | Oracle Community。可能会有所帮助。

      达里尔.伯克说:
      GridBagLayout 中的列(或行)定义不明确,除非至少有一个组件只占用该列(或行)。您的所有行都有跨越 2 列的组件。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-26
      • 2013-07-13
      • 2012-01-14
      • 1970-01-01
      • 1970-01-01
      • 2014-02-21
      相关资源
      最近更新 更多