GridBagLayout 中的 JScrollPanes 会随机调整大小

3
这是一个棘手的问题 :)
基本上,我有一个GridBagLayout,其中有两列:每个列中都有一个列表(list),并且用scrollpane包装。这些滚动窗格在 BOTH 方向上被拉伸。
如果我逐渐减少此面板的高度(通过拖动窗口的边缘),则会看到滚动窗格上发生“随机”调整大小:
  • 当第一个水平滚动条出现时,第二个的宽度会减小

  • 然后,第二个的宽度又因无法确定的原因而缩小...

如果我不包装我的组件,则不会出现此行为。
如果您用 tree 替换右侧列表,则会表现出不同的行为: 将窗口高度缩小到380-ich px以下,树会被调整大小...
如果我不包装我的组件,则无论如何调整窗口大小,树都会被调整大小!
你们有任何想法是怎么回事吗?
PS:我试图构建的实际布局比这个示例更复杂。同时,我使用SpringLayout来做我想要的事情,但需要设置太多(不太美观)的东西。
protected static ListModel newListModel(int n) {
    DefaultListModel lm = new DefaultListModel();

    for (int i = 0; i < n; ++i)
        lm.addElement("AAA");

    return lm;
}

protected static JComponent createContentPane() {
    JPanel  pane = new JPanel(new GridBagLayout());

    GridBagConstraints  gbc = new GridBagConstraints();

    gbc.anchor = GridBagConstraints.CENTER;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.weightx = 1;
    gbc.weighty = 1;
    gbc.gridy = 0;
    gbc.gridx = 0;

    pane.add(new JScrollPane(new JList(newListModel(12))), gbc);

    ++gbc.gridx;

    pane.add(new JScrollPane(new JList(newListModel(4))), gbc);

    return pane;
}

public static void main(String[] args) {
    JFrame f = new JFrame();

    f.getContentPane().add(createContentPane());
    f.setSize(800, 400);
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    f.setVisible(true);
}
2个回答

9

我有一个在GridBagLayout中包含多个ScrollPane的应用程序,当我调整窗口大小时它们会突然地改变大小。似乎是当ScrollPane的实际大小超过其“首选大小”时发生跳跃。我已经找到了一个解决方法:将首选大小设置为1x1像素。如果组件具有正权重并且同时拉伸,它仍将占据整个单元格,但不会跳跃。如果需要以不同比例调整大小的几个单元格,则可以将另一个单元格的首选大小设置为2x1像素。


哇,这解决了我的问题。我有一个类似的问题。我有一个4x4的网格,其中滚动窗格设置在右下角。我的约束是给右上角单元格权重,给左上角单元格垂直权重。所有其他单元格的权重都为0。我想要实现的是,如果我扩展包含该容器的对话框,那么只有顶部单元格会扩展,底部单元格会保持在底部。使用模拟面板时效果很好,但是由于我将右下角单元格设置为jscrollpne,因此会发生突然的调整大小。 所以我将首选大小设置为1,1。突然的跳跃不再发生,一切正常。 - Sa'ad
我因这个解决方案而爱你。 - Stefano L

2
这是GridBagLayout的基本原则,你忘记定义anchor,那么你就能够将JComponent固定到相对位置Point,而且我认为GridBagLayout会让你的GUI变得复杂,这种LayoutManager更适合在一个容器中放置许多JComponents(而不使用嵌套布局)。
例如:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class BorderPanels extends JFrame {

    private static final long serialVersionUID = 1L;

    public BorderPanels() {
        setLayout(new GridBagLayout());// set LayoutManager
        GridBagConstraints gbc = new GridBagConstraints();
        JPanel panel1 = new JPanel();
        Border eBorder = BorderFactory.createEtchedBorder();

        panel1.setBorder(BorderFactory.createTitledBorder(eBorder, "20pct"));
        gbc.gridx = gbc.gridy = 0;
        gbc.gridwidth = gbc.gridheight = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.anchor = GridBagConstraints.NORTHWEST;
        gbc.weightx = gbc.weighty = 20;
        add(panel1, gbc); // add compoenet to the COntentPane

        JPanel panel2 = new JPanel();
        panel2.setBorder(BorderFactory.createTitledBorder(eBorder, "60pct"));
        gbc.gridy = 1;
        gbc.weightx = gbc.weighty = 60;
        //gbc.insets = new Insets(2, 2, 2, 2);
        add(panel2, gbc); // add component to the COntentPane

        JPanel panel3 = new JPanel();
        panel3.setBorder(BorderFactory.createTitledBorder(eBorder, "20pct"));
        gbc.gridy = 2;
        gbc.weightx = gbc.weighty = 20;
        gbc.insets = new Insets(2, 2, 2, 2);
        add(panel3, gbc);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // important
        pack();
        setVisible(true); // important
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() { // important

            public void run() {
                BorderPanels borderPanels = new BorderPanels();
            }
        });
    }
}

避免把简单的事情复杂化


锚点已在我的示例中设置。无论我选择中心还是任何一个角落(比如西北角),我仍然遇到了这个问题。我的示例并没有显示我最终版本中的所有内容。我为了发布帖子而简化了它。实际上它更加复杂。 - Jordan
@Jordan 使用适当的LayoutManager,GridBagLayout是最复杂的LayoutManager并接受所有可能的参数,我认为你想要提供BoxLayout或BorderLayout,简单地选择其中一个。 - mKorbel

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