Swing中的可变布局

11

当你不知道会有多少组件以及它们的大小时,该如何生成一个外观不错的GUI?

例如,用户输入他们想要多少个文本框以及哪些文本框被分组在有边框的面板中,程序就会生成这些内容。

我一直在使用GridLayout,但问题是它使所有单元格的宽度和高度相同。当所有组件大小相同时,这很好,但是当我有一个文本框和一个带有多个字段的带边框面板时,文本框要么被拉伸,要么面板被压缩。

我希望所有组件都有它们的最小尺寸,但仍然可以使用。

这是现在的样子,使用GridLayout,所有字段都是普通的单行JTextField,其中标题为“日期”的面板被完全挤压(它有三个字段),而第一级字段则太大了。任何人有什么建议吗?

5个回答

15

MiGLayout很有吸引力,但BoxLayout也是一种替代方案。

image

import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;

public class BoxTest extends JPanel {

    private List<JTextField> fields = new ArrayList<JTextField>();

    public BoxTest() {
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.add(createPane(3, "One ", Color.red));
        this.add(createPane(3, "Two ", Color.green));
        this.add(createPane(10, "Three ", Color.blue));
    }

    private JPanel createPane(int n, String s, Color c) {
        JPanel outer = new JPanel();
        outer.setLayout(new BoxLayout(outer, BoxLayout.Y_AXIS));
        outer.setBorder(BorderFactory.createLineBorder(c, 2));
        for (int i = 0; i < n; i++) {
            JPanel inner = new JPanel();
            inner.setLayout(new BoxLayout(inner, BoxLayout.X_AXIS));
            JLabel label = new JLabel(s + i + ":", JLabel.RIGHT);
            label.setPreferredSize(new Dimension(80, 32));
            inner.add(label);
            JTextField tf = new JTextField("Stackoverflow!", 32);
            inner.add(tf);
            fields.add(tf);
            outer.add(inner);
        }
        return outer;
    }

    private void display() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JScrollPane jsp = new JScrollPane(this,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.validate();
        Dimension d = this.getPreferredSize();
        d.height /= 2;
        jsp.getViewport().setPreferredSize(d);
        jsp.getVerticalScrollBar().setUnitIncrement(
            this.getPreferredSize().height / fields.size());
        f.add(jsp);
        f.pack();
        f.setVisible(true);
    }

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

            @Override
            public void run() {
                new BoxTest().display();
            }
        });
    }
}

我现在唯一的问题是,当一个框中的标签不同时,文本框的大小也不同,就像这样http://grab.by/5gpW。有没有办法在不编写自己的LayoutManager的情况下解决这个问题? - thepandaatemyface
@thepandaatemyface:我已更新示例以展示一种方法。 - trashgod
@mKorbel 使用了“恰到好处”的词语:设置标签的首选大小是一种任意的hack。更精确的方法可能会使用本文中讨论的技术之一来找到最长的标签。这里提供了一些技巧。 - trashgod
2
+1 - 虽然我怀疑这也可能是使用GroupLayout的好例子,因为不需要设置标签的大小。 - Andrew Thompson
@AndrewThompson: 说得好!还可以看看这个使用GroupLayout示例 - trashgod

3
我建议使用miglayout。它比任何内置的布局管理器更有用。

3

您的总体目标是“可用组件尺寸”,但与“未知数量”相冲突。如果将数字设置得足够大,它们就无法适应任何屏幕。

如果您认为使用JTables(单元格可以进行编辑)与JScrollPanel结合使用会更好,请仔细考虑。如果您想/必须保持生成组件的方法,请将包含组件的整个JPanel放入JScrollPane中,这样组件就不会被压缩得太严重。


2

是的,MiGLayout很好用。使用它可以做很多事情。


1

AWT和Swing中的最小尺寸通常是无意义的。我建议添加一个面板来委托最小尺寸给原始首选尺寸,并可能在新的首选尺寸上添加一点。在GridBagLayout中添加权重,以便您希望额外空间进入正常大小的位置。正如Durandal所提到的,弹出顶层窗口周围的滚动条比挤压布局或走出屏幕更好(我正在Netbook上编写这篇文章,因此我知道有比屏幕更大的窗口)。


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