在JPanel中使JLabel居中

32

我有一个派生自JPanel的面板。我有一个派生自JLabel的自定义控件。我试图将这个自定义的JLabel居中在我的面板上。

我知道唯一可行的方法是使用空布局(setLayout(null)),然后计算自定义JLabelsetLocation()点,使其位于正确的位置。

这个自定义的JLabel会从一个面板物理移动到这个应用程序的另一个面板,并且我相信之前在setLocation中设置的位置会影响事情的发展。但是当我把它设置为(0,0)时,组件就会移到左上角。

BorderLayout不能工作,因为只提供了1个组件并放置在BorderLayout.CENTER中,中心部分会扩展以填充所有空间。

我从另一个站点剪切和粘贴的示例使用了BoxLayoutcomponent.setAlignmentX(Component.CENTER_ALIGNMENT)。但这也行不通。

另一个答案提到重写面板的getInset()函数(我想这就是它的名称),但这被证明是走不通的。

到目前为止,我正在使用一个带有GridBagLayout布局的面板,并在将自定义的JLabel插入我的面板时包含一个GridBagConstraints对象。然而这是低效的。是否有更好的方法来使JLabel居中于我的JPanel


10
考虑从抱怨中挖掘出实际问题的意思。 - Thorbjørn Ravn Andersen
哦,当我使用GridBagLayout和GridBagConstraints方法后,如果我最小化然后恢复主窗口,事情看起来还不错。 - Shackleford
3
写这篇长篇抱怨的时间足以在谷歌上输入“Swing与布局管理器配合使用”,点击官方Swing教程的第一个链接,查看视觉指南,决定BoxLayout看起来很有前途,并查看一个更或多或少符合您要求的示例(它包含两个组件而不是单个组件)。 - Robin
你的意思是我在相对详细地解释我所研究和尝试的事情时,这三个句子足以说明问题吗?我马上处理。 - Shackleford
5
Robin:虽然我已经清楚地提到了我找到和尝试过的各种事情,但我想我还是得说一下:我已经尝试过寻找答案了。这就是我在这里发布问题的原因。像你这样讽刺、自视甚高的评论在一个致力于帮助程序员找到问题答案的网站上是没有意义的。既然所有关于Java的信息都已经在网上某处有记录,那么没有什么问题是不能通过互联网搜索得到答案的。如果我的问题不符合你的标准,那么也许你不应该浪费太多时间来回复它。 - Shackleford
显示剩余2条评论
7个回答

50

JPanel 设置 GridBagLayout,将没有任何GridBagConstraintsJLabel 放置到 JPanel 上,JLabel 将居中显示。

enter image description here

示例

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

public class CenteredJLabel {

    private JFrame frame = new JFrame("Test");
    private JPanel panel = new JPanel();
    private JLabel label = new JLabel("CenteredJLabel");

    public CenteredJLabel() {
        panel.setLayout(new GridBagLayout());
        panel.add(label);
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(panel);
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                CenteredJLabel centeredJLabel = new CenteredJLabel();
            }
        });
    }
}

谢谢mKorbel不仅提供有用的信息,而且做得如此详尽。不幸的是,这让我陷入了同样的困境,即在放置JLabel后我的面板上没有任何东西出现。当我将您的示例插入到我的实际代码中并使用虚拟JButton时,JButton的位置完美无误。我甚至添加了一些设置来模仿我的自定义JLabel,它仍然有效,但是当我使用我的JLabel时?那就是事情不起作用的时候。我不明白。肯定有什么东西阻止了我的JLabel做这些虚拟JButton所做的事情。 - Shackleford
无法工作:java.lang.IllegalArgumentException: cannot add to layout: constraints must be a GridBagConstraint。-1 - Cardinal System

21

假设您的JLabel被称为label,那么使用:

label.setHorizontalAlignment(JLabel.CENTER);

5
错误的是它影响了标签内容的位置,而不是标签在容器中的位置。 - Kroky

10

忘记Java标准库中的所有LayoutManager,使用MigLayout。 根据我的经验,它更容易使用并且通常会按照您的期望进行操作。

以下是使用MigLayout实现您想要的内容的方法。

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class Test
{
    public static void main( String[] args )
    {
        JFrame frame = new JFrame( );
        JPanel panel = new JPanel( );

        // use MigLayout
        panel.setLayout( new MigLayout( ) );

        // add the panel to the frame
        frame.add( panel );

        // create the label
        JLabel label = new JLabel( "Text" );

        // give the label MigLayout constraints
        panel.add( label, "push, align center" );

        // show the frame
        frame.setSize( 400, 400 );
        frame.setVisible( true );
    }
}
大部分内容都是样板代码,关键在于布局约束:"push, align center"align center 告诉 MigLayout 将 JLabel 放置在其网格单元格的中心。 push 告诉 MigLayout 扩展网格单元格以填充可用空间。

有一个很棒的MigLayout备忘单可以在以下网址找到:http://migcalendar.com/miglayout/mavensite/docs/cheatsheet.html - ulmangt
您可以从这里下载最新版本的MigLayout:http://www.migcalendar.com/miglayout/versions/4.0/miglayout-4.0-swing.jar - ulmangt
有趣!谢谢你的提示,我将来会记住这个,但现在我希望能够在Java库中找到所需的东西。我还是很新,正在努力学习。 - Shackleford
我怀疑大多数人不会想在像这样的琐事上使用外部库。使用外部库使您的程序合法并不难,但为什么要浪费律师的时间和金钱呢?您可以使用Java标准库来完成它。而且,使用MigLayout的代码并不比JavaSE布局更简单。我认为它甚至更加复杂,因为在向“容器”添加组件约束时,似乎与LayoutManager相关的语法也会出现。 - searchengine27
这看起来像是我多年来一直错过的东西!我迫不及待想试试。+1 - Cardinal System

9

BoxLayout是可行的方案。如果您设置了一个X_AXIS BoxLayout,请在组件前后添加水平粘合剂:

panel.add(Box.createHorizontalGlue());
panel.add(label);
panel.add(Box.createHorizontalGlue());

2

我不喜欢这里的答案。

在我的职业生涯中,我从未见过 GridBagLayout 的有效用途。并不是说没有,只是我没见过 [有效的] 用途,可能有一些相关性。此外,将单个 JLabel 添加到 Container 的中间可能会使其居中以进行演示,但如果您尝试继续使用它而不是其他布局,则以后会更加困难。

我确实喜欢 BoxLayout 的建议,因为那是一个很好的方法。也就是说,那个答案只是谜题的一部分,这就是为什么我要挖掘一个七年前的问题。

我的“答案”

实际上,对于你的问题,没有简短的答案。根据你所问的问题,有一个确切的答案,但 StackOverflow 是关于社区互相学习的,我猜你想学习如何使用布局(或者你七年前想学习),告诉你输入一组键来完成你的演示案例并不能教你答案。

我将尽量避免解释任何你自己无法通过网络搜索找到答案的布局(但最后会提供一个指向Oracle教程的链接,因为我认为它相当好地解释了不同的布局)。

BoxLayout

BoxLayout是一种实现方法,上面已经有一个演示它的代码片段,所以我不会再提供一个。我会扩展一下,只回答了您的问题,但并没有真正教您什么。Box容器中被称为“Glue”的组件基本上给您在所有“Glue”之间提供平均的剩余空间。因此,如果您像这样做:

panel.add(Box.createHorizontalGlue());
panel.add(label);
panel.add(Box.createHorizontalGlue());
panel.add(otherLabel);

你会发现你的JLabel不再居中,因为“glue”只是剩余的空间,在两个JLabels被添加到Container之后,这些空间将被平均分配给两个“插槽”(即在Container中使用带有粘合参数的两个Container#add(Component)调用)。

BorderLayout

BorderLayout是另一种方法。BorderLayout被分成5个区域。BorderLayout#CENTER,正如你所想象的那样,是中心区域。关于这种布局和它如何居中的重要说明是它遵守位于中心的Component的大小。我不会详细介绍这一点;如果你感兴趣,Oracle教程已经很好地涵盖了这一点。

值得注意的地方

我想你可以使用GridLayout,但这是一个更简单的方法,比GridBagLayout更简单,我已经说过,即使我认为这也不是一个好的方法。所以我也不会详细介绍这个。

所有这些的重点

说了这么多,我认为所有的布局管理器都值得一看。就像与编程有关的任何其他东西一样 - 使用适合工作的工具。不要仅仅因为你之前使用过X布局,就认为你应该总是使用X布局,而没有其他可行的布局方式。确定您想要的显示效果,以及您认为应如何调整组件大小,然后选择您认为最适合的。

另一个选择正确工具的双重意义在于,您不必只将所有组件适配到一个单独的容器中,并使一个布局执行所有操作。没有什么能阻止您(我强烈鼓励您这样做)使用多个容器并将它们全部分组。对每个显示区域使用适当的布局控制每个容器,并对不同的容器使用不同的布局。

重要!!

这个非常重要的原因是因为每个布局都有它们遵循的规则和事项,以及其他它们尊重的事项,还有一些实际上被忽略的事项(例如首选、最大和最小大小)。如果你正确地使用不同的布局,你会发现你的显示屏可以动态地被调整大小,同时仍然遵守你想要保持的形状。这是正确做法和只满足于GridBagLayout之间非常重要的关键区别。
JPanel outer = new JPanel(new BorderLayout());
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.PAGE_AXIS));
JPanel southPanel = new JPanel(new CardLayout());

outer.add(centerPanel, BorderLayout.CENTER);
outer.add(southPanel, BorderLayout.SOUTH);

找出适合您场景的内容,并选择它。除非您想要一些过于繁琐并被其他布局所取代的东西,否则没有一种大小适合所有。

Oracle的教程

如果您已经走到了这一步,那么我认为您正在寻找尽可能多的信息。在这种情况下,我强烈建议您阅读Oracle的布局管理器教程,因为它很好地概述了它们的一般细节:https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html


0
不使用库和布局,可以像这样编程:
JLabel jlabel = new JLabel("标签文本", SwingConstants.CENTER);
确保导入javax.swing.SwingConstants接口,但不要实现它。 它仅包含常量而没有方法。
将JLabel放在JPanel中,否则它将出现在JFrame或JWindow(您的顶级容器)的中心位置。

0
使用这个。
labelName.setHorizontalAlignment(SwingConstants.CENTER);

或者

labelName.setHorizontalAlignment(JPanel.CENTER);

两者都必须工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接