GridBagLayout不稳定的大小调整和显示

时间:2015-05-28 00:13:56

标签: java swing layout-manager gridbaglayout

我正在制作一个在容器中使用GridBagLayout的程序。我的主要用途是拥有两个JPanel,它占据窗口水平空间的75%和25%。但是出于某种原因,这两个面板看起来更像90/10,并且在调整大小时,较小的面板会迅速改变尺寸,在它的表观最小尺寸和我认为理想的25%之间。

以下是相关代码。

frmReedreadV = new JFrame();
    frmReedreadV.setBounds(x, y, width, height);
    frmReedreadV.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frmReedreadV.getContentPane().setLayout(new BoxLayout(frmReedreadV.getContentPane(), BoxLayout.Y_AXIS));

    JPanel stretchyPanel = new JPanel();
    frmReedreadV.getContentPane().add(stretchyPanel);
    stretchyPanel.setLayout(new CardLayout(0, 0));

    JPanel textAndUsers = new JPanel(new GridBagLayout());

    GridBagConstraints gbc = new GridBagConstraints();
    gbc.fill = GridBagConstraints.BOTH;

    gbc.weighty = 1;

    textArea = new JTextArea();
    textArea.setMargin(new Insets(2, 5, 5, 2));
    textArea.setLineWrap(true);
    textArea.setWrapStyleWord(true);
    textArea.setEditable(false);

    scrollPane = new JScrollPane(textArea);
    scrollPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));

    gbc.weightx = 0.8;
    textAndUsers.add(scrollPane, gbc);

    list = new FriendsList(listUpdate);

    gbc.weightx = 0.2;
    textAndUsers.add(list.frmUserList, gbc);

    stretchyPanel.add(textAndUsers);

FriendsList是JPanel中包含的JList。

主CardLayout内容窗格中还有其他按钮和文本字段,但那些不应该影响此GridBagLayout内部的内容,对吗?

我将此JPanel的另一个副本作为独立应用程序制作,并且它完美地显示和调整大小。见这里:

JFrame frame = new JFrame();
    frame.getContentPane().setLayout((new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(100, 100, 550, 600);

    JPanel stretchyPane = new JPanel();
    frame.getContentPane().add(stretchyPane);
    stretchyPane.setLayout(new CardLayout(0, 0));

    JPanel panel = new JPanel(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    JTextArea text = new JTextArea();
    text.setMargin(new Insets(2, 5, 5, 2));
    JScrollPane panel1 = new JScrollPane(text);
    FriendsList panel2 = new FriendsList(new Object());

    c.fill = GridBagConstraints.BOTH;
    c.weightx = .8;
    c.weighty = 1;
    panel.add(panel1, c);
    c.weightx = .2;
    //c.fill = GridBagConstraints.HORIZONTAL;
    panel.add(panel2.frmUserList, c);

    stretchyPane.add(panel);

    frame.setVisible(true);

由于我已将原始行逐行复制到副本中,可能导致两者之间存在差异?

1 个答案:

答案 0 :(得分:1)

weightx和weighty属性似乎可以作为比例大小,但这不是他们所做的。实际上,它们决定了布局中额外空间的分布。

如果通过在JFrame上调用pack()将所有内容设置为首选大小,则不会有额外空间。这意味着weightx和weighty属性在该状态下没有任何效果。

一旦用户开始调整窗口大小,就会有额外的空间,然后GridBagLayout才会查询weightx和weighty属性,以确定如何将额外空间分配给每个列和行。在此之前,如果它们的首选尺寸决定了,那么重量较小的部件完全有可能比具有较大重量的部件宽。

希望这个简单的程序能够展示这个概念。尝试使用鼠标(或键盘)将窗口调整为更宽,并观察每个文本字段的增长情况:

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GridBagProportions {
    static void buildAndShowWindow() {
        JTextField small = new JTextField("small (0.8)", 5);
        JTextField large = new JTextField("LARGE (0.2)", 30);

        small.setMinimumSize(small.getPreferredSize());
        large.setMinimumSize(large.getPreferredSize());

        JPanel panel = new JPanel(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets.left = 6;
        gbc.insets.top = 6;
        gbc.insets.bottom = 6;

        gbc.weightx = 0.8;
        panel.add(small, gbc);

        gbc.weightx = 0.2;
        gbc.insets.right = 6;
        panel.add(large, gbc);

        JFrame frame = new JFrame("GridBagLayout Proportions");
        frame.getContentPane().add(panel);
        frame.pack();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                buildAndShowWindow();
            }
        });
    }
}

那么可以做些什么呢?嗯,这是GridBagLayout无法做到的一种布局方案。我会尝试使用SpringLayout

SpringLayout layout = new SpringLayout();
JPanel textAndUsers = new JPanel(layout);

SpringLayout.Constraints scrollPaneConstraints =
    new SpringLayout.Constraints(scrollPane);

Spring scrollPaneWidth = scrollPaneConstraints.getWidth();
SpringLayout.Constraints listConstraints =
    new SpringLayout.Constraints(scrollPaneWidth,
                                 scrollPaneConstraints.getY(),
                                 Spring.scale(scrollPaneWidth, 0.25f),
                                 scrollPaneConstraints.getHeight());

layout.putConstraint(SpringLayout.EAST, textAndUsers, 0,
                     SpringLayout.EAST, frmUserList);
layout.putConstraint(SpringLayout.SOUTH, textAndUsers, 0,
                     SpringLayout.SOUTH, scrollPane);

textAndUsers.add(scrollPane, scrollPaneConstraints);
textAndUsers.add(frmUserList, listConstraints);

请注意,listConstraints的创建指定了宽度参数Spring.scale(scrollPaneWidth, 0.25f)。这样可以确保列表的宽度始终是包含JTextArea的scrollPane的四分之一。

SpringLayout使用起来很棘手,因为你必须确保明确地将布局容器的远边链接到子组件,因为SpringLayout不会增长以自动容纳所有子组件。这就是putConstraint调用的内容。