为什么需要使用 BoxLayout 调用 setLayout?

9
大多数布局管理器都有无参数构造函数(也就是说,您可以使用`new FlowLayout()`创建一个FlowLayout,使用`new GridLayout()`创建一个GridLayout,使用`new GridBagLayout()`创建一个GridBagLayout等)。但是,`BoxLayout`要求您传递它将要管理的容器以及应该布置组件的轴线。
我的问题是:既然您已经告诉布局管理器要布置哪个组件,为什么还需要编写“箱”来指定要使用哪个轴线?
BoxLayout bl = new BoxLayout(myPanel, BoxLayout.Y_AXIS);
myPanel.setLayout(bl);

如何获取BoxLayout的全部代码而不仅仅是第一行?

我快速查看了BoxLayout源代码,发现我使用的构造函数(178-185行)没有调用target.setLayout(this)或类似的内容。看起来很容易添加这个功能。Swing库为什么没有包含它呢?

如果有影响的话,我正在使用:

java版本1.7.0

Java(TM) SE Runtime Environment (build 1.7.0-b147)

在Win7Pro上。

谢谢!


SSCCE:

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;

public class BoxLayoutSSCCE extends JFrame {

    // Change this to see what I mean
    public static final boolean CALL_SET_LAYOUT = true;

    public BoxLayoutSSCCE () {
        super("Box Layout SSCCE");
        JPanel panel = new JPanel();
        BoxLayout bl = new BoxLayout(panel, BoxLayout.Y_AXIS);
        if (CALL_SET_LAYOUT) {
            panel.setLayout(bl);
        }
        panel.add(new JButton("Button 1"));
        panel.add(new JButton("Button 2"));
    }

    public static void main (String[] args) {
        BoxLayoutSSCCE blsscce = new BoxLayoutSSCCE();
        blsscce.pack();
        blsscce.setVisible(true);
    }
}

1
+1 for sscce - trashgod
2个回答

5

在将Container传递给BoxLayout之前,它必须存在。通常情况下,我们会编写类似以下的代码:

JPanel myPanel = new JPanel();
BoxLayout bl = new BoxLayout(myPanel, BoxLayout.Y_AXIS);
myPanel.setLayout(bl);

很诱人将最后两行合并,但最少惊奇原则建议布局的构造函数不应该改变容器的状态。
方便地,javax.swing.Box 提供了“使用 BoxLayout 对象作为其布局管理器的轻量级容器”。
public class Box extends JComponent implements ... {

    public Box(int axis) {
        super();
        super.setLayout(new BoxLayout(this, axis));
    }
}

现在只需要一行代码:
Box myBox = new Box(BoxLayout.Y_AXIS);

不用谢;作为参考,该设计与此处讨论的原则保持一致(https://dev59.com/mXA75IYBdhLWcg3wPmZ8#3404369)。 - trashgod

4
< p > BoxLayout 确保布局方法应用于正确的容器。它强制要求在构造函数中指定的同一容器被用于各种方法,如 layoutContainer(Container target)preferredLayoutSize(Container target) 等等。这归结于 checkContainer() 方法进行验证:

void checkContainer(Container target) {
    if (this.target != target) {
        throw new AWTError("BoxLayout can't be shared");
    }
}
BoxLayout 的实现可能会缓存容器的一些细节并尝试维护状态,因此它不能被共享。
编辑: BoxLayout 实现了 LayoutManager2.invalidateLayout(),在其中重置其缓存的详细信息。其他布局实现也遵循相同的模式。例如,GroupLayoutOverlayLayout 也需要在它们的构造函数中传入容器参数。

我明白它不能被共享。然而,既然它不能被共享,那么组件将不得不将其设置为其布局似乎是合乎逻辑的 - 为什么BoxLayout在构造函数中不直接调用setLayout(container)呢?此外,为什么其他管理器没有强制执行这一点呢? - wchargin
@WChargin 构造函数中指定的参数用于BoxLayout验证和应用限制。此外,请参阅我的编辑有关其他管理器的内容。 - tenorsax

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