【问题标题】:Getting a panel within a JLayeredPane to stretch in a BorderLayout让 JLayeredPane 中的面板在 BorderLayout 中拉伸
【发布时间】:2020-11-10 13:18:00
【问题描述】:

我的基本安排如下:

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

左侧面板位于JFrameBorderLayoutWEST 一侧,JLayeredPane 位于CENTER 中。如何让 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 会扩展,因此默认(和其他?)层中的面板会扩展,但似乎都没有。这应该怎么做?

【问题讨论】:

  • 错误消息表明您正在调用方法add(Component, Object),但第二个方法参数是int,而不是Object。也许如果您愿意edit 您的问题并发布minimal reproducible example,我也许可以帮助您解决这个问题。或者您只需将int 更改为Integer
  • 在 JLayeredPane 上设置BorderLayout 的尝试是在黑暗中刺伤;我希望有人知道它应该如何完成,而不是仅仅尝试或多或少随机的东西来看看它是否有效。我可以花一些时间从根本不是最小的东西中提取一个例子,但我并不是试图避免这个错误消息,我试图找出应该如何做到这一点。我很满意自己在 JLayeredPane 上设置 BorderLayout 不是这样。
  • 我想添加一个面板,该面板将具有空布局,并且我将使用它进行绝对定位。如果我转储 JLayeredPane 的大小和首选大小,我分别得到 38,61 和 1,1——我不知道 38,61 来自哪里。我希望这个中间区域成为用户可以拖放图像的面板,所以我希望它能够扩展以适应可用空间。这就是我想弄清楚该怎么做。

标签: java swing border-layout jlayeredpane


【解决方案1】:

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

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

  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。

【讨论】:

  • 当然看起来更容易——还有一个问题,对原版的轻微补充:分层窗格的全部意义在于允许在拖动层上拖动;我为它创建的示例程序创建了一个“玻璃窗格”JPanel,并在拖动时将其分配给分层窗格的 DRAG_LAYER。但我不认为我会将 middlePanel 和 glassPanel 都分配给borderLayout面板的CENTER,或者我会这样做吗?我需要这个玻璃面板与中间面板的尺寸相同并覆盖它,我该怎么做?
  • 在我回答的最后一个问题中,您要求澄清。我更新了我的答案,提供了更多信息,但从未收到您的来信。在这个问题中,您得到了一个可行的解决方案并且没有“接受”答案。然后我提供了一个您说更容易的解决方案,但您仍然没有“接受”这个答案。相反,你只是继续问另一个不相关的问题。这不是20个问题。每个帖子一个问题。如果您有新问题,请创建您的“MRE”并将其发布在新问题中。
  • 顺便说一句,我以前从未使用过像我的答案这样的代码。我刚刚阅读了 JLayeredPane API,试图更好地理解它是如何工作的。这就是我在分层窗格如何工作的概述中看到 setLayer(...) 方法的地方。此外,如果您在面板周围拖动组件,则无需使用 JLayeredPanel 和拖动层。只需在面板周围拖动即可。
  • 如果您被冒犯了,我深表歉意;我没有在我/我们的最后一个问题上添加其他评论,因为我对此没有其他要说的,而且我被告知不要使用 cmets 表示“谢谢”。我只是还没来得及标记这个答案。我不认为我的问题“完全不相关”,但这是一个不同的问题,所以我会以不同的方式处理它。我非常感谢您在 SO 上为 Swing 答案所做的所有工作。
【解决方案2】:

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

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 大小以匹配内容窗格的新大小。

【讨论】:

  • 因此,您将获得主窗口的内容窗格并将 JLayeredPane 中的面板大小设置为该值。但我们真正想要的是将尺寸设置为主窗口中心部分的尺寸,而不是整个尺寸。如果在创建和设置边框的调用中将, 3 放在Color.blue 之后,您可以看到面板的右侧边缘没有显示边框;我认为那是因为窗口实际上现在太大了。有没有一种在调整大小时获得中间部分尺寸的好方法?
  • 我只是尝试创建一个默认的 JPanel 放在 JFrame 的中间,然后将 JLayeredPane 放在那个面板中,并保持其他内容相同。我希望调整新 JPanel 的大小可以让我为 otherPanel 设置新尺寸;确实调用了它的componentResized() 方法,并执行您编写的相同代码,但没有显示边框。我不知道otherPanel 去了哪里。
  • 如果我理解问题所在,应该将 ComponentListener 添加到分层窗格,而不是内容窗格。我只是将 ComponentListener 逻辑移动到 getMiddlePanel() 方法,以便可以将侦听器添加到分层窗格中。
  • 好的,这解决了边框不显示的问题——我将组件监听器更改为中间面板,消除了我尝试的额外面板,现在边框显示在所有 4 个边上,表示调整后的面板按我的意愿填充边框布局的中心。所以调整大小事件转到 JLayeredPane,然后我们编写代码来调整它包含的面板的大小?代码从 JLayeredPane 中执行getSize(),实际上它正在使用 JFrame 进行扩展。我希望我知道我怎么能告诉它会那样做;我知道面板会,但不是 JLayeredPane。
  • @arcy JLayeredPane 是一个类似于 JPanel 或 JButton 的组件。添加到 BorderLayout 的“CENTER”的任何组件都将自动调整大小。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
相关资源
最近更新 更多