请帮助我理解BoxLayout对齐问题

5
我正在尝试使用Java布局创建一个非常简单的窗口。我有三个元素需要排列:一个按钮,一个进度条和一个标签。按钮必须垂直居中,进度条必须占据整个宽度,标签必须左对齐。
以下是一些代码(假设pane是JFrame的内容面板,并且在之前已经创建了button、progressBar和label):
BoxLayout layout = new BoxLayout(pane, BoxLayout.Y_AXIS);
pane.setLayout(layout);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(button);
progressBar.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(progressBar);
label.setAlignmentX(Component.LEFT_ALIGNMENT);
pane.add(label);

当我测试应用程序时,发现所有东西都错位了:按钮和标签的缩进是随机的,如果我调整窗口的大小,缩进量会以奇怪的方式改变。 进度条看起来很好(全宽)。

我不明白到底出了什么问题。你能给我一个提示吗?


1
个人而言,我从来不信任setAlignmentX或setAlignmentY,并尽量避免它们,我还会避免完全依赖它们的布局管理器。 - jfpoilpret
1
我现在明白你为什么这样做了... 你有什么替代方案建议吗? - gd1
如果你必须坚持使用纯JDK,那么在你的情况下我可能会使用GridBagLayout;这将很好地工作,因为你的布局很简单(当你的布局有更多组件时,GBL开始变得复杂)。否则,我会使用DesignGridLayout。 - jfpoilpret
5个回答

7

BoxLayout无法处理不同的对齐方式:请参见http://download.oracle.com/javase/tutorial/uiswing/layout/box.html

引用该文章中的一句话:“通常情况下,由从上到下的BoxLayout对象控制的所有组件应具有相同的X对齐方式。类似地,由从左到右的BoxLayout对象控制的所有组件通常应具有相同的Y对齐方式。”


谢谢,所以BoxLayout对我来说很糟糕。我会遵循你的所有提示。 - gd1
你确定它不能处理不同的对齐方式吗?http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html - Andrew S
@AndrewS:当您建议Box可以处理不同的对齐方式时,您指的是教程的哪个部分?解决方案是否涉及使用Box.createHorizontalGlue(),或者还有其他方法实现? - mins
@Mins,请看图像示例标题为BoxLayoutDemo2的部分。你会发现组件是使用Component.LEFT_ALIGNMENT、Component.CENTER_ALIGNMENT和Component.RIGHT_ALIGNMENT相对于彼此对齐的。 - Andrew S
@AndrewS:这对我不起作用,我在这个问题中发布了代码。有什么问题吗? - mins
@mins 查找同一文档中演示粘合的部分,然后尝试在所需组件的前面或后面放置粘合。您还可以尝试嵌套布局。 - Andrew S

5
有时候你需要有创意地使用嵌套面板。但是我更喜欢这种方法,而不是试图学习和记忆使用其他布局管理器(GridBagLayout、GroupLayout)所需的所有约束条件,因为它们是为生成代码的IDE设计的。
import java.awt.*;
import javax.swing.*;

public class BoxLayoutVertical extends JFrame
{
    public BoxLayoutVertical()
    {
        Box box = Box.createVerticalBox();

        JButton button = new JButton("A button");
        button.setAlignmentX(Component.CENTER_ALIGNMENT);
        box.add(button);

        JProgressBar progressBar = new JProgressBar(0, 100);
        progressBar.setAlignmentX(Component.CENTER_ALIGNMENT);
        box.add(progressBar);

        JPanel panel = new JPanel( new BorderLayout() );
        JLabel label = new JLabel("A label");
        label.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.add(label);
        box.add(panel);

        add(box, BorderLayout.NORTH);
    }

    public static void main(String[] args)
    {
        BoxLayoutVertical frame = new BoxLayoutVertical();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.setSize(300, 200);
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }
}

最好的解决方案,因为它不涉及任何额外的库、类,而且它针对我正在面对的问题进行了定制。然而,在学习更多有关布局的知识方面,我会遵循其他用户的解决方案,但在这种情况下,我正在寻找一种简单的技巧。 - gd1

2
为了补充我的评论,这里提供一个使用DesignGridLayout的代码片段:
JButton button = new JButton("Button");
JProgressBar progressBar = new JProgressBar();
JLabel label = new JLabel("Label");

// The interesting stuff is in the next 4 lines
DesignGridLayout layout = new DesignGridLayout(getContentPane());
layout.row().center().add(button).withOwnRowWidth();
layout.row().center().fill().add(progressBar);
layout.row().left().add(label);

pack();

它完全按照您在问题中描述的方式进行操作,并且不需要调用任何组件。

1

不要使用BoxLayout。它只适用于非常简单的情况。

对于您的情况,我建议使用GridBagLayout或(我最喜欢的)GroupLayout。


对于GroupLayout,我创建了一个子类(LayoutHelper),其中包含一些实用方法和有用的构造函数,使编写布局更加容易。
当然,通常我将组中的所有组件都以相同的方式对齐,所以在你的情况中,它可能并不像在简单情况下那么简短。
    LayoutHelper h = new LayoutHelper(pane);

    h.setVerticalGroup
        ( h.sequential( button, progressBar, label));

    h.setHorizontalGroup
        ( ((ParallelGroup)h.parallel())
          .addComponent(button, Alignment.CENTER)
          .addComponent(progressBar)
          .addComponent(label, Alignment.TRAILING));

这是一个屏幕截图:

screenshot

对于一个简单的“所有内容都对齐”的横向组,它看起来会像这样:

    h.setHorizontalGroup
        ( h.parallel (button, progressBar, label));

(可选地带有第一个参数指示对齐方式)。


@Paulo 你是手写GroupLayout吗?那么你似乎有太多的空闲时间 :-) - kleopatra
@kleopatra: 我有一个包装类可以稍微简化一下(我会添加使用这个类的样例)。一个简单的 GroupLayout 并不好,但也比 GridBagLayout 好不了多少。 - Paŭlo Ebermann
@Giacomo:老实说,我不知道 BoxLayout 有什么好处。我使用它时也遇到了很多问题,特别是在其布局方向正交的对齐方面。 - Paŭlo Ebermann

1

也许你的代码只是一小段,但我错过了对pack()的调用。

手动编写Swing布局可能会非常令人沮丧,使用标准布局管理器。 我使用MiG Layout以实现这一目的。 它很直接,并且您只需几行代码即可获得漂亮的布局。 如果您不必使用BoxLayout,则建议您尝试一下。


我喜欢这个MiG布局,但我真的不想链接其他JAR并将事情推向更“复杂”的水平,因为这是一个非常简单的应用程序。 - gd1
@Giacomo:好的,没问题;)那么“缺失”的pack()不是问题了? - das_weezul

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