获取 JLayeredPane 中的面板以在 BorderLayout 中拉伸

Getting a panel within a JLayeredPane to stretch in a BorderLayout

我有以下基本安排:

+--- JFrame ---------------------------------------+
| +-- Panel --+ +-- JLayeredPane ----------------+ |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| |           | |                                | |
| +-----------+ +--------------------------------+ |
+--------------------------------------------------+

左边的面板在 JFrameBorderLayoutWEST 一侧,JLayeredPaneCENTER 的一侧。如何让 JLayeredPane 的 DEFAULT 层上的面板随着 JFrame 的大小拉伸?

我尝试在 JLayeredPane 上设置 BorderLayout,但失败了:

Caused by: java.lang.reflect.InvocationTargetException
  at java.awt.EventQueue.invokeAndWait(EventQueue.java:1349)
  at java.awt.EventQueue.invokeAndWait(EventQueue.java:1324)
  at org.rc.vitruvius.Vitruvius.main(Vitruvius.java:17)
Caused by: java.lang.IllegalArgumentException: cannot add to layout: constraint must be a string (or null)
  at java.awt.BorderLayout.addLayoutComponent(BorderLayout.java:426)
  at java.awt.Container.addImpl(Container.java:1130)
  at javax.swing.JLayeredPane.addImpl(JLayeredPane.java:231)
  at java.awt.Container.add(Container.java:975)

我正在使用 add(Component, LayerConstant),我猜这与边框布局不兼容。

编辑:这里有一个小例子来说明:

package sandbox;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class JLayeredPaneProblem extends JFrame
{
  private static final long serialVersionUID = 1L;

  public static void main(String[] args)
  {
    JLayeredPaneProblem main = new JLayeredPaneProblem();
    main.go();
  }
  
  public void go()
  {
    createMainUI();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
  }
  
  private void createMainUI()
  {
    JPanel leftPanel = getLeftPanel();
    Component middlePanel = getMiddlePanel(getOtherPanel());
    
    add(leftPanel, BorderLayout.WEST);
    add(middlePanel, BorderLayout.CENTER);
    pack();
  }
  
  private Component getMiddlePanel(JPanel wrappedPanel)
  {
    JLayeredPane middlePanel = new JLayeredPane();
    middlePanel.add(wrappedPanel, JLayeredPane.DEFAULT_LAYER);
    return middlePanel;
  }
  
  private JPanel getOtherPanel()
  {
    JPanel otherPanel = new JPanel();
    Dimension size = new Dimension(100,100);
    otherPanel.setSize(size);
    otherPanel.setPreferredSize(size);
    otherPanel.setBorder(BorderFactory.createLineBorder(Color.blue));
    return otherPanel;
  }
  
  private JPanel getLeftPanel()
  {
    JPanel innerPanel = new JPanel();
    innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.PAGE_AXIS));
    JButton button = new JButton("button");
    String [] items = { "One", "Two", "Three" };
    JComboBox<String> cbox = new JComboBox<>(items);
    innerPanel.add(button);
    innerPanel.add(cbox);
    
    JPanel leftPanel = new JPanel();
    leftPanel.add(innerPanel);
    
    
    return leftPanel;
  }
}

如您所见,中间的面板(蓝色边框可以看出它的边框在哪里)没有展开;我可能期望 JLayeredPane 会扩展,因此默认(和其他?)层中的面板会扩展,但其中 none 似乎会扩展。这应该如何完成?

我相信这可以满足您的需求。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class JLayeredPaneProblem extends JFrame
{
  private static final long serialVersionUID = 1L;
  private static JPanel otherPanel;
  public static void main(String[] args)
  {
    JLayeredPaneProblem main = new JLayeredPaneProblem();
    main.getContentPane().addComponentListener(new ComponentListener() {
        
        @Override
        public void componentShown(ComponentEvent e) {
            // Do nothing.
        }
        
        @Override
        public void componentResized(ComponentEvent e) {
            System.out.println("componentResized()");
            otherPanel.setPreferredSize(e.getComponent().getSize());
            otherPanel.setMaximumSize(e.getComponent().getSize());
            otherPanel.setSize(e.getComponent().getSize());
            otherPanel.revalidate();
            otherPanel.repaint();
        }
        
        @Override
        public void componentMoved(ComponentEvent e) {
            // Do nothing.
        }
        
        @Override
        public void componentHidden(ComponentEvent e) {
            // Do nothing.
        }
    });
    main.go();
  }
  
  public void go()
  {
    createMainUI();
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setVisible(true);
  }
  
  private void createMainUI()
  {
    JPanel leftPanel = getLeftPanel();
    Component middlePanel = getMiddlePanel(getOtherPanel());
    
    add(leftPanel, BorderLayout.WEST);
    add(middlePanel, BorderLayout.CENTER);
    pack();
  }
  
  private Component getMiddlePanel(JPanel wrappedPanel)
  {
    JLayeredPane middlePanel = new JLayeredPane();
    middlePanel.add(wrappedPanel, JLayeredPane.DEFAULT_LAYER);
    return middlePanel;
  }
  
  private JPanel getOtherPanel()
  {
    otherPanel = new JPanel();
    Dimension size = new Dimension(100,100);
    otherPanel.setSize(size);
    otherPanel.setPreferredSize(size);
    otherPanel.setBorder(BorderFactory.createLineBorder(Color.blue));
    return otherPanel;
  }
  
  private JPanel getLeftPanel()
  {
    JPanel innerPanel = new JPanel();
    innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.PAGE_AXIS));
    JButton button = new JButton("button");
    String [] items = { "One", "Two", "Three" };
    JComboBox<String> cbox = new JComboBox<>(items);
    innerPanel.add(button);
    innerPanel.add(cbox);
    
    JPanel leftPanel = new JPanel();
    leftPanel.add(innerPanel);
    
    return leftPanel;
  }
}

JLayeredPane 似乎考虑了其包含的组件的不同大小。因此,您需要动态更改这些大小以响应顶层大小的变化 JFrame.

为了知道顶层 JFrame 何时调整大小,我在 JFrame 的内容窗格中添加了一个 ComponentListener 并且每当内容窗格大小发生变化时,我设置otherPanel 大小以匹配内容窗格的新大小。

I tried setting a BorderLayout on the JLayeredPane, but it fails with...:

正常添加组件,然后设置图层:

  private Component getMiddlePanel(JPanel wrappedPanel)
  {
    JLayeredPane middlePanel = new JLayeredPane();
    //middlePanel.add(wrappedPanel, JLayeredPane.DEFAULT_LAYER);
    middlePanel.setLayout(new BorderLayout() );
    middlePanel.add(wrappedPanel, BorderLayout.CENTER);
    middlePanel.setLayer(wrappedPanel, JLayeredPane.DEFAULT_LAYER);
    return middlePanel;
  }

使用这种方法不需要 ComponentListener。