Search code examples
javalayout-managergrid-layoutgridbaglayout

How to vertically fill a JPanel with GridLayout or GridBagLayout?


I want to fill a JPanel whose layout is GridLayout, if it's not possible using GridLayout i would like to know if using GridBagLayout is possible and how?

Here's the code:

public class NestedLayoutExample {

public static void main(String[] args) {

    Runnable r = new Runnable() {

        @Override
        public void run() {
            final JFrame frame = new JFrame("Nested Layout Example");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setMinimumSize(new Dimension(300, 400));

            final JPanel gui = new JPanel(new BorderLayout(5,5));
            gui.setBorder( new TitledBorder("BorderLayout(5,5)") );

            JPanel dynamicLabels = new JPanel(new BorderLayout(4,4));
            dynamicLabels.setBorder( new TitledBorder("BorderLayout(4,4)") );
            gui.add(dynamicLabels, BorderLayout.CENTER);

            final JPanel labels = new JPanel(new GridLayout(4,0,3,3));
            labels.setBorder( new TitledBorder("GridLayout(0,2,3,3)") );

            JButton addNew = new JButton("Add Another Label");
            dynamicLabels.add( addNew, BorderLayout.NORTH );
            addNew.addActionListener( new ActionListener(){
                private int labelCount = 0;

                @Override
                public void actionPerformed(ActionEvent ae) {
                    labels.add( new JLabel("Label " + ++labelCount) );
                    frame.validate();
                }
            } );

            dynamicLabels.add( new JScrollPane(labels), BorderLayout.CENTER );

            frame.setContentPane(gui);
            frame.pack();
            frame.setLocationRelativeTo(null);
            try {
                // 1.6+
                frame.setLocationByPlatform(true);
                frame.setMinimumSize(frame.getSize());
            } catch(Throwable ignoreAndContinue) {}

            frame.setVisible(true);
        }
    };
    SwingUtilities.invokeLater(r);
}}

This is what I get the code above:

enter image description here

And this is what I want:

enter image description here

Also would like to know about a better way to do it.


Solution

  • This is a "slight" step in the direction your looking for...

    GridBagLayout

    If you want it to work a little more like GridLayout (so that the first series of labels appear on the top/left), you're going to have to include some "filler" objects that make up the initial grid...

    import java.awt.BorderLayout;
    import java.awt.ComponentOrientation;
    import java.awt.Dimension;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.SwingUtilities;
    import javax.swing.border.TitledBorder;
    
    public class NestedLayoutExample {
    
        public static void main(String[] args) {
    
            Runnable r = new Runnable() {
    
                @Override
                public void run() {
                    final JFrame frame = new JFrame("Nested Layout Example");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setMinimumSize(new Dimension(300, 400));
    
                    final JPanel gui = new JPanel(new BorderLayout(5, 5));
                    gui.setBorder(new TitledBorder("BorderLayout(5,5)"));
    
                    JPanel dynamicLabels = new JPanel(new BorderLayout(4, 4));
                    dynamicLabels.setBorder(new TitledBorder("BorderLayout(4,4)"));
                    gui.add(dynamicLabels, BorderLayout.CENTER);
    
                    final JPanel labels = new JPanel(new GridBagLayout());
                    labels.setBorder(new TitledBorder("GridLayout(0,2,3,3)"));
    
                    JButton addNew = new JButton("Add Another Label");
                    dynamicLabels.add(addNew, BorderLayout.NORTH);
                    addNew.addActionListener(new ActionListener() {
    
                        private int labelCount = 0;
                        private int gridx = 0;
                        private int gridy = 0;
    
                        @Override
                        public void actionPerformed(ActionEvent ae) {
                            GridBagConstraints gbc = new GridBagConstraints();
                            gbc.weightx = 1;
                            gbc.weighty = 1;
                            gbc.gridx = gridx;
                            gbc.gridy = gridy;
                            labels.add(new JLabel("Label " + ++labelCount), gbc);
                            labels.revalidate();
    
                            gridy++;
                            if (gridy >= 4) {
                                gridy = 0;
                                gridx++;
                            }
                        }
                    });
    
                    dynamicLabels.add(new JScrollPane(labels), BorderLayout.CENTER);
    
                    frame.setContentPane(gui);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    try {
                        // 1.6+
                        frame.setLocationByPlatform(true);
                        frame.setMinimumSize(frame.getSize());
                    } catch (Throwable ignoreAndContinue) {
                    }
    
                    frame.setVisible(true);
                }
            };
            SwingUtilities.invokeLater(r);
        }
    }