我应该使用什么设置来解决这个 GridBagLayout 大小调整问题?

What settings should I use to resolve this GridBagLayout resizing issue?

我一直在搜索并尝试解决 GridBagLayout 调整大小时遇到​​的问题,但无济于事。问题是:

  1. 我将 JDialog window 的底部向下拖动以使其更高;搜索面板(下面屏幕截图中的面板上方)不断变高,只是添加了它不需要的白色 space 内容(我不想浪费这个 space ,它会占用高度它下面的滚动 table)。

  2. 如果我移动 window 的右侧使其变窄一点,即使我的屏幕和 window 可以显示,滚动面板也会变得太短它的全高;出现垂直滚动条(我不喜欢面板垂直滚动,只是水平滚动。)

我的 JDialog 在右上部分包含下面的组件,使用下面的布局管理器和约束:

JPanel      level 1         uses GridBagLayout Setting 1 (see below)
JScrollPane level 2         uses GridBagLayout Setting 1  
JPanel      level 3         uses GridBagLayout Setting 2
JPanel      level 4         uses GridBagLayout Setting 2
JPanel      level 5         uses GridBagLayout Setting 2
JPanel      level 5         uses GridBagLayout Setting 2

GridBagLayout.GridBagConstraints (c)

设置 1:

c.fill = GridBagConstraints.BOTH;
c.weightx = 99.0;
c.weighty = 99.0;

设置 2:

c.fill = GridBagConstraints.NONE;
c.weightx = 1.0;
c.weighty = 1.0;

原来这是我的JDialog如果我不用JScrollPane:

如果我拖动 window 使其变大,JPanel 的大小(这是我在使用 JScrollPane 使其水平滚动之前使用的大小)保持不变这是。我想实现相同的行为,只是我想让它水平滚动。

我应该使用什么布局管理器来解决这个大小调整问题?如果我真的必须使用GridBagLayout,我应该使用什么constraints/settings?我将不胜感激任何建议。谢谢!

更新 1 -------------------------------------- --------------

请检查下面的示例代码场景。两个可滚动面板(红色和蓝色)都使用 GridBagConstraints.BOTHweightxweighty 等于 99.0。我希望红色面板的高度足以包含文本字段。我还希望当对话框被向下拖动以使 window 变大时,红色面板的高度保持不变。请注意,在实际屏幕中,两个面板的内容数量可能会发生变化(存在 add/minus 个按钮),因此,设置最小面板尺寸(用于调整大小)将无济于事。请建议我应该如何处理这个案子。谢谢!

package cfr.view.search;

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

import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class GBLSample extends JDialog {

    private JPanel contentPane;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    GBLSample frame = new GBLSample();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public GBLSample() {
        setBounds(100, 100, 350, 400);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        GridBagLayout gbl_contentPane = new GridBagLayout();
        contentPane.setLayout(gbl_contentPane);

        // RED PANEL ------------------------------------------------ 
        JScrollPane sp1 = new JScrollPane();
        GridBagConstraints gbc1 = new GridBagConstraints();
        gbc1.fill = GridBagConstraints.BOTH;
        gbc1.weightx = 99.0;
        gbc1.weighty = 99.0;
        contentPane.add(sp1, gbc1);

        JPanel redPanel = new JPanel();
        redPanel.setBackground(Color.RED);
        JTextField field = new JTextField(20);
        GridBagConstraints gbc2 = new GridBagConstraints();
        gbc2.anchor = GridBagConstraints.PAGE_START;
        gbc2.fill = GridBagConstraints.NONE;
        contentPane.add(field, gbc2);

        redPanel.add(field);
        sp1.setViewportView(redPanel);

        // BLUE PANEL ------------------------------------------------ 
        JScrollPane sp2 = new JScrollPane();
        GridBagConstraints gbc3 = new GridBagConstraints();
        gbc3.fill = GridBagConstraints.BOTH;
        gbc3.gridx = 0;
        gbc3.gridy = 1;
        gbc3.weightx = 99.0;
        gbc3.weighty = 99.0;
        contentPane.add(sp2, gbc3);

        JPanel bluePanel = new JPanel();
        bluePanel.setBackground(Color.BLUE);
        sp2.setViewportView(bluePanel);
    }
}

更新 2 -------------------------------------- --------------

JPanel 的大小调整仍然存在与上述 #1 相同的问题。 问题 1

试试这个代码:

package test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;

public class GridBagLayoutSample extends JFrame {

private JPanel contentPane;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                GridBagLayoutSample frame = new GridBagLayoutSample();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public GridBagLayoutSample() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    GridBagLayout gbl_contentPane = new GridBagLayout();
    gbl_contentPane.columnWidths = new int[]{0, 0};
    gbl_contentPane.rowHeights = new int[]{50, 0, 0};
    //the 1.0 value in columnWeights let redPanel and scrollPane (that contain bleuPanel) grow horizontally
    //the 1.0 value is in the first index so it affect the first column
    //you still need to use a valid value for gbc_redPanel.fill and gbc_scrollPane.fill;
    gbl_contentPane.columnWeights = new double[]{1.0, Double.MIN_VALUE};
    //the 0.0 value of rowWeights => components in first row will not grow
    //the 0.0 value of rowWeights => components in second row will grow
    gbl_contentPane.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
    contentPane.setLayout(gbl_contentPane);

    JPanel redPanel = new JPanel();
    redPanel.setBackground(Color.RED);
    GridBagConstraints gbc_redPanel = new GridBagConstraints();
    gbc_redPanel.insets = new Insets(0, 0, 5, 0);
    gbc_redPanel.fill = GridBagConstraints.BOTH;
    gbc_redPanel.gridx = 0;
    gbc_redPanel.gridy = 0;
    contentPane.add(redPanel, gbc_redPanel);

    JScrollPane scrollPane = new JScrollPane();
    GridBagConstraints gbc_scrollPane = new GridBagConstraints();
    gbc_scrollPane.fill = GridBagConstraints.BOTH;
    gbc_scrollPane.gridx = 0;
    gbc_scrollPane.gridy = 1;
    contentPane.add(scrollPane, gbc_scrollPane);

    JPanel bleuPanel = new JPanel();
    bleuPanel.setBackground(Color.BLUE);
    //scrollpane work with the preferred size of the component in the viewportView
    //try to change this values
    bleuPanel.setPreferredSize(new Dimension(400, 400));
    scrollPane.setViewportView(bleuPanel);
}

}

将此添加到您的代码中

gbl_contentPane.rowHeights = new int[]{40, 0, 0};
gbl_contentPane.rowWeights = new double[]{0.0,0.0, 1.0, Double.MIN_VALUE};
gbc1.gridx = 0;
gbc1.gridy = 0;

并删除这个

gbc1.weightx = 99.0;
gbc1.weighty = 99.0;

I have been searching and trying ways to resolve the problems I encountered with GridBagLayout resizing but to no avail.

欢迎来到GridBagLayout

首先要注意的是在

        JPanel redPanel = new JPanel();
        redPanel.setBackground(Color.RED);
        JTextField field = new JTextField(20);
//      GridBagConstraints gbc2 = new GridBagConstraints();
//      gbc2.anchor = GridBagConstraints.PAGE_START;
//      gbc2.fill = GridBagConstraints.NONE;
//      contentPane.add(field, gbc2);

        redPanel.add(field);
        sp1.setViewportView(redPanel);

您正在将文本字段添加到内容窗格,然后再次将其添加到面板,这会覆盖您之前的分配(一个组件只能属于一个容器)。我注释掉了什么都不做的行。选择如何在红色面板中布置文本字段与如何在内容窗格中布置红色面板的选择完全不同。

I want the red panel to have a height that is enough to contain the text field.

这是由布局管理器处理的。但是,如果您手动调整 window 的大小,使面板没有足够的 space,那么只要面板位于 JScrollPane 中,滚动条就会出现。您可以尝试 @Override 面板的 getMinimumSize 到其 getPreferredSize,但我相信并非所有布局管理器都尊重它。

无论如何,我根本不明白为什么你需要红色面板的滚动窗格。

I also want that when the dialog is dragged down to make the window bigger, the red panel's height remains the same.

那么你应该将它的weighty设置为0

注意:不要在non-final变量名中使用下划线(_),按照Java命名约定(gbl_contentPane 应该是 gblContentPane).

编辑

下面是动态更改 redPanel 的分配大小的示例。为简单起见,我将 BorderLayout 用于内容窗格(也由 Dan O 建议)。

public class GBLSample extends JDialog {

    private JPanel contentPane;
    private JScrollPane redSP = new JScrollPane(new RedPanel());

    public static void main(String[] args) {

        EventQueue.invokeLater(() -> {
            GBLSample frame = new GBLSample();
            frame.setVisible(true);
        });
    }

    private class RedPanel extends JPanel {

        RedPanel() {

            setLayout(new GridBagLayout());
            setBackground(Color.RED);

            GridBagConstraints c = new GridBagConstraints();
            c.anchor = GridBagConstraints.FIRST_LINE_START;
            add(new JTextField(10), c);
            c.weightx = 1;
            c.gridx = 1;
            add(new JComboBox<>(), c);
            c.weightx = 0;
            c.gridx = 0;
            add(new JComboBox<>(), c);
            c.gridx = 1;
            add(new JComboBox<>(), c);
            c.weighty = 1;
            c.gridx = 0;
            c.gridy = 2;
            add(new JButton("SSSS"), c);
        }

        @Override
        public Dimension getPreferredSize() {

            Dimension dim = super.getPreferredSize();
            JScrollBar sb = redSP.getHorizontalScrollBar();
            if (!sb.isShowing())
                return dim;
            return new Dimension(dim.width, dim.height + sb.getHeight());
        }
    }

    public GBLSample() {

        setBounds(100, 100, 350, 400);
        contentPane = new JPanel(new BorderLayout());
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);

        // RED PANEL ------------------------------------------------
        redSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        contentPane.add(redSP, BorderLayout.PAGE_START);

        // BLUE PANEL ------------------------------------------------
        JPanel bluePanel = new JPanel();
        bluePanel.setBackground(Color.BLUE);
        contentPane.add(new JScrollPane(bluePanel));
    }
}

想法是通过将所有权重赋予底部的组件来在面板底部添加所有额外的 space(类似地可以使用 [=53= 对 x 轴完成] 零件)。当显示滚动条时,面板会重新计算其高度并将滚动条的高度添加到自身(最底部的组件),然后滚动条不会隐藏任何内容。

也许 GridBagLayout 可能不适合您当前的 UI,而 BorderLayout 会更好吗?将红色面板放在 BorderLayout.NORTH 中,将蓝色面板放在 BorderLayout.CENTER 中。当您调整对话框大小时,CENTER 区域中的组件将增大和缩小,并且您的红色面板的 preferredSize 将在您 +/- 项目时得到尊重。

不幸的是,系统被覆盖的 JPanel.getMinimumSize() 中存在一个错误,导致我的搜索面板被压缩不复存在。我已经能够找到修复它的方法,而无需使用系统的自定义布局管理器更改任何设置。不过,非常感谢您的所有回答和帮助。