如何将两个 JPanel 添加到中心的 JFrame?

Posted

技术标签:

【中文标题】如何将两个 JPanel 添加到中心的 JFrame?【英文标题】:How to add two JPanels to a JFrame in the center? 【发布时间】:2013-12-09 13:53:59 【问题描述】:

我正在创建一个游戏,它有一张背景图片,上面显示有卡片。我想放置背景图像和卡片,使它们始终垂直和水平居中,即使在调整 JFrame 大小时也是如此。

目前,我正在创建卡片(每个 JPanel)并将它们添加到容器 JPanel(无布局管理器)中,然后将该 Jpanel 添加到 JFrame。之后,我将背景图像放在 JPanel 中,然后将该 JPanel 添加到 JFrame。结果是:背景图像隐藏在卡片后面,并在根据需要移除每张卡片时显示出来。背景图像始终居中,但卡片的 JPanel 在调整大小时不会移动。无论我尝试什么,我都很难让卡片始终居中。我还需要在南部边界的 JFrame 中添加另一个 JPanel,这样它也需要工作。感谢您的帮助!

在扩展 JFrame 的类中:

setSize(1060,700);

cardPanel = new JPanel();
cardPanel.setSize(1060,700);
cardPanel.setOpaque(false);
cardPanel.setLayout(null);
...card.setLocation(x, y); //loop through cards
...cardPanel.add(card); //and add each one
add(cardPanel, BorderLayout.CENTER); //add cardPanel to JFrame

//Add background image
bgPanel = new JPanel();
URL url = getClass().getResource("images/dragon_bg.png"); 
imgIcon = new ImageIcon(url);
JLabel background = new JLabel(imgIcon);
bgPanel.setLayout(new BorderLayout());
bgPanel.add(background);
add(bgPanel, BorderLayout.CENTER);

setVisible(true);

【问题讨论】:

1) Java GUI 可能必须在多个平台、不同的屏幕分辨率和使用不同的 PLAF 上工作。因此,它们不利于组件的精确放置。要为强大的 GUI 组织组件,请改用布局管理器或 combinations of them,以及 white space 的布局填充和边框。 2) 为了尽快获得更好的帮助,请发帖SSCCE。 【参考方案1】:

我想放置背景图像和卡片,使其始终垂直和水平居中,即使在调整 JFrame 大小时也是如此。

然后您需要在面板上使用布局管理器。布局管理器负责重做布局。

如何将两个 JPanel 添加到一个 JFrame 的中心?

您可以尝试为此使用 OverlayLayout。我认为基本代码是:

JPanel contentPane = new JPanel( new GrigBagLayo9ut() );
frame.add(contentPane, BorderLayout.CENTER);

JPanel overlay = new JPanel()
overlay.setLayout( new OverlayLayout(overlay) );
contentPane.add(overlay, new GridBagConstraints()); // this should center the overlay panel

overlay.add(yourCardPanel); // you care panel must use a suitable layout
overlay.add(new JLabel() ); // use a JLabel for the background not a custom panel

我还需要在南边的JFrame中再添加一个JPanel,

JFrame 内容窗格的默认布局管理器是 BorderLayout。我们已经将游戏面板添加到了中心,因此您只需将其他面板添加到 SOUTH。

如果 OverlayLayout 不能按您想要的方式工作,那么您将需要嵌套面板。比如:

JPanel center = new JPanel( new GridBagLayout() );
frame.add(center, BorderLayout.CENTER);

JLabel background = new JLabel(...);
background.setLayoutManager( new GridBagLayout() );
center.add(background, new GridBagConstraints());

background.add(yourCardPanel, new GridBagConstraints());

编辑:

使用嵌套面板:

import java.awt.*;
import javax.swing.*;

public class GridBagLayoutCenter extends JPanel

    public GridBagLayoutCenter()
    
        setLayout( new BorderLayout() );

        JLabel background = new JLabel( new ImageIcon("mong.jpg") );
        background.setLayout( new GridBagLayout() );

        add(background, BorderLayout.CENTER);

        JPanel tiles = new JPanel();
        tiles.setPreferredSize( new Dimension(200, 200) );
        tiles.setBackground( Color.RED );
        background.add(tiles, new GridBagConstraints());

        add(new JLabel("SOUTH"), BorderLayout.SOUTH);
    

    private static void createAndShowUI()
    
        JFrame frame = new JFrame("GridBagLayoutCenter");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new GridBagLayoutCenter() );
        frame.setSize(400, 400);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    

    public static void main(String[] args)
    
        EventQueue.invokeLater(new Runnable()
        
            public void run()
            
                createAndShowUI();
            
        );
    

不应硬编码“图块”面板的首选大小。大小应由您的自定义布局管理器根据您添加到面板的图块确定。大小不应随着瓷砖被移除而改变。

【讨论】:

感谢 camickr。没有布局管理器适用于我的 cardPanel,所以我手动设置了每张卡片的位置。我用 Grid Bag 尝试了覆盖,它几乎可以正常工作。卡片在图形的顶部,它们都在调整大小时移动,但它们在右侧和底部被切断,并且在框架中没有完全居中。我试过玩 setSize 但这没有做任何事情。感谢您的建议。 No layout manager will work for my cardPanel, - 你为什么这么说?您可以轻松嵌套面板以获得所需的效果。 I tried playing with setSize but that's not doing anything. 布局经理希望设置首选大小,而不是大小。 我可以嵌套面板,但卡片面板需要没有布局管理器,否则我的设计很难实现。如果我用 setPreferredSize 替换 setSize 它只会呈现标题栏。 @Jordan, 指定尺寸适用于面板。您添加到使用布局管理器的另一个面板的任何面板都必须具有适当的首选大小,以便布局管理器可以完成其工作。这就是您使用布局管理器的原因,因此您不必通过手动硬编码一些首选尺寸的值来重新发明***。我无法建议您适合哪种布局管理器,因为您没有给出任何要求,但您始终可以实现自己的自定义“卡片布局管理器”。 我已经为卡片面板实现了我的自定义布局,除了非居中的情况外,它运行良好。框架我设置它的大小,卡片面板我必须设置它的大小,我没有设置大小,也没有设置覆盖或 contentPane 的首选大小。请参阅我添加的屏幕截图。感谢您的帮助,非常感谢!【参考方案2】:

我最终决定将背景图像放在卡片面板本身中,然后将卡片面板放在盒子布局管理器中,使其始终居中。我将 cardPanel 重命名为 gameBoard。绝对可以更清洁,但我只能满足我的要求。

setSize(new Dimension(1000, 600));
gameBoard = new JPanel();
gameBoard.setLayout(null);
gameBoard.setOpaque(false);
Dimension expectedDimension = new Dimension(920, 500);
gameBoard.setPreferredSize(expectedDimension);
gameBoard.setMaximumSize(expectedDimension);
gameBoard.setMinimumSize(expectedDimension);
//add cards to gameBoard here

JLabel background = new JLabel( new ImageIcon( getClass().getResource("images/graphic.png") ) );
background.setLocation(79,0); //manually center graphic
background.setBounds(new Rectangle(0, 0, 920, 500));
gameBoard.add(background);

Box centerBox = new Box(BoxLayout.Y_AXIS);
centerBox.setOpaque(true); 
centerBox.setBackground(Color.WHATEVER);
centerBox.add(Box.createVerticalGlue());
centerBox.add(gameBoard);
centerBox.add(Box.createVerticalGlue());
add(centerBox);
setVisible(true);

【讨论】:

-1,硬编码值不支持您对动态调整大小的要求。 none of them worked for me. - 我发布了一个工作示例。图像不是在框架中居中吗?红色面板是否不在图像中心?它怎么不适合你?我给你的代码适用于使用空布局的磁贴面板。这怎么不满足你的要求?花时间了解解决方案。如果我发布的示例没有反映您的框架的结构,那么反映您的结构的代码在哪里。这就是 SSCCE 的用途。 它肯定是动态调整大小的。我告诉过你我的确切要求:固定的中间面板在框架动态调整大小时始终保持居中。我无法改变我的要求,所以 -1 me 因为那是荒谬的。不幸的是,我在没有使用您的建议的情况下解决了这个问题,因为我花了几个小时尝试每一个,但最终都没有奏效。 我给你的代码按原样工作。一切都以中心为中心。您需要做的就是将一些组件添加到“图块”面板并调整首选大小。 didn't work in the end - 这没有描述问题。什么不起作用?您进行了更改并破坏了代码。当您不描述问题时,您如何期望帮助?使用 BoxLayout 并不是一个糟糕的解决方案。这是使组件居中的第二种最常见的方式。使用 GridBagLayout 更容易,因为您无需担心胶水。如果 BoxLayout 有效,那么 GridBagLayout 也应该有效。

以上是关于如何将两个 JPanel 添加到中心的 JFrame?的主要内容,如果未能解决你的问题,请参考以下文章

如何将自定义的 MouseMotionListener 添加到 JPanel?

如何将 JPanel 添加到 JFrame 十次 [重复]

如何将 JLabels 动态添加到 JPanel?

如何将调整大小箭头添加到JPanel?

如何在JFrame上显示带有图像的两个JPanel,并且两个img都可见?

在 Java 中单击按钮在 JPanel 中绘制一条线