Java 带胶水的GridBagLayout:无固定行高

Java 带胶水的GridBagLayout:无固定行高,java,swing,layout-manager,gridbaglayout,Java,Swing,Layout Manager,Gridbaglayout,我想创建一个面板,我可以在其中动态添加具有固定高度的子面板。我尝试使用胶水组件,但它不起作用。我希望实现子面板在gridbaglayout的顶部可见。另一个问题是,当我不断添加子面板时,它们开始重叠,因为JScrollPane没有调整。然而,当我调整框架的大小时,这两个问题都得到了解决 此时此刻,我看不出我错在哪里了。为什么胶水组件不占用垂直空间将侧板推到顶部 这是我的SSCCE代码: import javax.swing.*; import java.awt.GridBagLayout; im

我想创建一个面板,我可以在其中动态添加具有固定高度的子面板。我尝试使用胶水组件,但它不起作用。我希望实现子面板在gridbaglayout的顶部可见。另一个问题是,当我不断添加子面板时,它们开始重叠,因为JScrollPane没有调整。然而,当我调整框架的大小时,这两个问题都得到了解决

此时此刻,我看不出我错在哪里了。为什么胶水组件不占用垂直空间将侧板推到顶部

这是我的SSCCE代码:

import javax.swing.*;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import jrdb.data.ProcessingCommand;

public class ProcessingPipelineBuilderSSCCE extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 2413084448601918744L;
    private JPanel interiorPanel = null;
    private GridBagConstraints gbc = null;
    private Component glue = null;

    public ProcessingPipelineBuilderSSCCE() {
        super("SSCCE");
        this.getContentPane().setLayout(new BorderLayout());

        gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 0, 5);
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.weighty = 1.0;
        gbc.anchor = GridBagConstraints.PAGE_START;

        JPanel pipelineBuilder = new JPanel();
        pipelineBuilder.setLayout(new GridLayout(0, 1, 0, 0));

        interiorPanel = new JPanel(new GridBagLayout());
        interiorPanel.setBorder(BorderFactory.createLineBorder(Color.red));
        JScrollPane scrollPane = new JScrollPane(interiorPanel);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setPreferredSize(new Dimension(500,300));
        pipelineBuilder.add(scrollPane);

        JButton btnNew = new JButton("Add new panel");
        btnNew.setPreferredSize(new Dimension(500, 30));
        btnNew.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (glue!=null) {
                    interiorPanel.remove(glue);
                } else {
                    glue = Box.createGlue();
                }
                gbc.gridy = gbc.gridy + 1;
                interiorPanel.add(new PipelineStep(gbc.gridy),gbc);
                interiorPanel.add(glue,gbc);
                interiorPanel.validate();
                interiorPanel.repaint();
            }
        });
        this.getContentPane().add(btnNew, BorderLayout.PAGE_START);

        this.getContentPane().add(pipelineBuilder,BorderLayout.CENTER);


    }

    public class PipelineStep extends JPanel {
        int number;
        public PipelineStep (int n) {
            super();
            JOptionPane.showMessageDialog(interiorPanel, "adding new panel");
            this.number = n;
            this.setLayout(new FlowLayout());
            JLabel lbl = new JLabel(new Integer(this.number).toString());
            lbl.setPreferredSize(new Dimension(45,45));
            lbl.setFont(lbl.getFont().deriveFont(26));
            this.add(lbl);
            this.setPreferredSize(new Dimension(450, 50));
            this.setBorder(BorderFactory.createLineBorder(Color.green));
        }
    }

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

}
为什么胶水组件不占用垂直空间将侧板推到顶部

“粘合”组件仅在与BoxLayout一起使用时才有意义。它对GridBagLayout没有影响

所以我的建议是忘记GridBagLayout而使用BoxLayout

最简单的方法是将“interiorPanel”转换为使用垂直框,然后将您的
PipelineStep
实例添加到此面板

试试这个。但是,您会注意到,在滚动窗格已满之前,面板的大小仍将增加,此时您将看到滚动条出现。这是因为BoxLayout会将组件的大小调整到组件的最大大小。因此,为了防止这种大小调整,您可以覆盖
PipelineStep
类的
getMaximumSize()
方法:

@Override
public Dimension getMaximumSize()
{
    return getPreferredSize();
}
或者,另一种选择是使用“包装器”面板作为“内饰面板”。比如:

JPanel wrapper = new JPanel( new BorderLayout() );
wrapper.add(interiorPanel, BorderLayout.PAGE_START);
//JScrollPane scrollPane = new JScrollPane(interiorPanel);
JScrollPane scrollPane = new JScrollPane(wrapper);
BorderLayout.PAGE_START
尊重添加到其中的组件的首选高度,因此“interiorPanel”将始终以其首选高度显示,滚动窗格的视口已满时将显示滚动条

我使用“包装器”方法修改了您的代码

import javax.swing.*;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

//import jrdb.data.ProcessingCommand;

public class SSCCE1 extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = 2413084448601918744L;
//    private JPanel interiorPanel = null;
    private Box interiorPanel = null;
    private GridBagConstraints gbc = null;
    private Component glue = null;

    public SSCCE1() {
        super("SSCCE");
        this.getContentPane().setLayout(new BorderLayout());

        gbc = new GridBagConstraints();
        //gbc.insets = new Insets(5, 5, 0, 5);
        //gbc.fill = GridBagConstraints.HORIZONTAL;
        //gbc.gridx = 0;
        //gbc.gridy = 0;
        //gbc.weightx = 1.0;
        //gbc.weighty = 1.0;
        //gbc.anchor = GridBagConstraints.PAGE_START;

        JPanel pipelineBuilder = new JPanel();
        pipelineBuilder.setLayout(new GridLayout(0, 1, 0, 0));

//        interiorPanel = new JPanel(new GridBagLayout());
        interiorPanel = Box.createVerticalBox();
        interiorPanel.setBorder(BorderFactory.createLineBorder(Color.red));

        JPanel wrapper = new JPanel( new BorderLayout() );
        wrapper.add(interiorPanel, BorderLayout.PAGE_START);

//        JScrollPane scrollPane = new JScrollPane(interiorPanel);
        JScrollPane scrollPane = new JScrollPane(wrapper);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPane.setPreferredSize(new Dimension(500,300));
        pipelineBuilder.add(scrollPane);

        JButton btnNew = new JButton("Add new panel");
        btnNew.setPreferredSize(new Dimension(500, 30));
        btnNew.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
//                if (glue!=null) {
//                    interiorPanel.remove(glue);
//                } else {
//                    glue = Box.createGlue();
//                }
                gbc.gridy = gbc.gridy + 1;
//                interiorPanel.add(new PipelineStep(gbc.gridy),gbc);
                interiorPanel.add(new PipelineStep(gbc.gridy),gbc);
//                interiorPanel.add(glue,gbc);
//                interiorPanel.validate();
                interiorPanel.revalidate();
                interiorPanel.repaint();
            }
        });
        this.getContentPane().add(btnNew, BorderLayout.PAGE_START);

        this.getContentPane().add(pipelineBuilder,BorderLayout.CENTER);


    }

    public class PipelineStep extends JPanel {
        int number;
        public PipelineStep (int n) {
            super();
            JOptionPane.showMessageDialog(interiorPanel, "adding new panel");
            this.number = n;
            this.setLayout(new FlowLayout());
            JLabel lbl = new JLabel(new Integer(this.number).toString());
            lbl.setPreferredSize(new Dimension(45,45));
            lbl.setFont(lbl.getFont().deriveFont(26));
            this.add(lbl);
            this.setPreferredSize(new Dimension(450, 50));
            this.setBorder(BorderFactory.createLineBorder(Color.green));
        }
    }

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

}

您需要做的一件事是更改
validate()
。在按钮侦听器中执行
revalidate()
。您好,WJS,谢谢您的回复!更改为
revalidate()
确实解决了滚动条问题,但组件占用的空间仍然超出需要。您好,camickr,感谢您的回复。我将尝试实现它,并检查您的解决方案。我也希望能够拖放面板,但我仍然必须首先开始阅读。如果你有什么好的建议,它们总是受欢迎的…它成功了!我能不能让面板水平安装在水平方向上?我不知道你在问什么。如果使用“包装器”方法,面板将水平增长,框架宽度将增加。如果将帧缩小到小于首选宽度,则会自动显示滚动条。