GridBagLayout elements behaviour when resizing window

1.2k Views Asked by At

I'm new to Java Swing and was trying to make a simple layout (I thought), but I have a lot of problems reaching the behavior I want. Here's my code :

    setSize(800, 600);       
    setLocationRelativeTo(null);                     
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

    equipementPanel.setPreferredSize(new Dimension(275, 300));
    grillePanel.setPreferredSize(new Dimension(300, 600));

    GridBagConstraints c = new GridBagConstraints();

    c.gridx = 0; c.gridy = 0;
    c.anchor = GridBagConstraints.NORTHWEST;
    c.gridwidth = 1; c.gridheight = 1;
    c.weightx = 0.0; c.weighty = 0.0;
    this.add(equipementPanel, c);

    c.fill = GridBagConstraints.BOTH;
    c.gridx = 0; c.gridy = 1;
    c.anchor = GridBagConstraints.SOUTHWEST;
    c.gridwidth = 1; c.gridheight = 2;
    c.weightx = 0.0; c.weighty = 0.0;
    this.add(informationPanel, c);

    c.fill = GridBagConstraints.HORIZONTAL;
    c.gridx = 1; c.gridy = 0;
    c.anchor = GridBagConstraints.NORTHEAST;
    c.weightx = 1.0; c.weighty = 1.0;
    this.add(grillePanel, c);

    c.fill = GridBagConstraints.BOTH;
    c.gridx = 1; c.gridy = 1;
    c.anchor = GridBagConstraints.SOUTHEAST;
    c.weightx = 1.0; c.weighty = 0.0;
    this.add(commandePanel, c);

    this.validate();

Screen of my laptop is a good result of what I want.

  1. equipementPanel = green
  2. grillePanel = gray

enter image description here

But on my bigger screen...it is the gray one that should stretch. Red it's okay.

enter image description here

And a total disaster when I size it down .

enter image description here

What I want it to do is
The Gray should not have fixed height and width.
The Yellow should always have the fixed height but not width.
The Red should always have fixed width but not height. The Green should always have both fixed.

The smallest the window could become would be set to the height of the Green + Yellow one. and width of Green + whatever nice to display.

I know that the weird behavior with the small window is because I go under 300 + 600 of my preferred size...but I need to fix some size somewhere!?!?

If I can reach the same behavior with another layout, I'd be glad to try it. If I change and use some ScrollPanel, does that change anything?

I added a mcve : MCVE.JAVA

package mcve;
import java.awt.EventQueue;
public class MCVE {
 /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            mcve.gui.MainWindow mainWindow  = new mcve.gui.MainWindow();
            mainWindow.setVisible(true);
        });
    }
}

MainWindow.Java

package mcve.gui;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;

public class MainWindow extends JFrame 
{ 
    public MainWindow() 
    {
        this.setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.setLayout(new GridBagLayout()); 
        initComponents();
    }

    private void initComponents() 
    {                             
        setSize(800, 600);       
        setLocationRelativeTo(null);                     
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

        GrillePanel grillePanel = new GrillePanel();
        CommandePanel commandePanel = new CommandePanel();
        InformationPanel informationPanel = new InformationPanel();
        EquipementPanel equipementPanel = new EquipementPanel();

        equipementPanel.setPreferredSize(new Dimension(275, 300));
        grillePanel.setPreferredSize(new Dimension(300, 600));

        GridBagConstraints c = new GridBagConstraints();

        c.gridx = 0; c.gridy = 0;
        c.anchor = GridBagConstraints.NORTHWEST;
        c.gridwidth = 1; c.gridheight = 1;
        c.weightx = 0.0; c.weighty = 0.0;
        this.add(equipementPanel, c);

        c.fill = GridBagConstraints.BOTH;
        c.gridx = 0; c.gridy = 1;
        c.anchor = GridBagConstraints.SOUTHWEST;
        c.gridwidth = 1; c.gridheight = 2;
        c.weightx = 0.0; c.weighty = 0.0;
        this.add(informationPanel, c);

        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 1; c.gridy = 0;
        c.anchor = GridBagConstraints.NORTHEAST;
        c.weightx = 1.0; c.weighty = 1.0;
        this.add(grillePanel, c);

        c.fill = GridBagConstraints.BOTH;
        c.gridx = 1; c.gridy = 1;
        c.anchor = GridBagConstraints.SOUTHEAST;
        c.weightx = 1.0; c.weighty = 0.0;
        this.add(commandePanel, c);

        this.validate();
    }    
}

the 4 panel

package mcve.gui;

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class InformationPanel extends JPanel 
{
    public InformationPanel()
    {
        setBackground(Color.red);
        setBorder(BorderFactory.createLineBorder(Color.black));
        setVisible(true);
    }

}

package mcve.gui;

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class GrillePanel extends JPanel
{
    public GrillePanel()
    {
        setBackground(Color.lightGray);
        setBorder(BorderFactory.createLineBorder(Color.black));
        setVisible(true);
    }
}

package mcve.gui;

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class EquipementPanel extends JPanel 
{
    public EquipementPanel()
    {
        setBackground(Color.green);
        setBorder(BorderFactory.createLineBorder(Color.black));
        setVisible(true);
    }

}

package mcve.gui;

import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JPanel;

public class CommandePanel extends JPanel 
{
    public CommandePanel()
    {
        setBackground(Color.yellow);
        setBorder(BorderFactory.createLineBorder(Color.black));
        setVisible(true);
    }

}
2

There are 2 best solutions below

1
On BEST ANSWER

There are two basic issues (as I see it)...

One, you are trying to manage a complex layout within a single layout manager, which is pretty hard at the best of times.

Two, you don't seem to understand what the layout manager will do when the available size of the component drops below it's preferred size, which is, in the case of GridBagLayout, revert to it's minimum size...

You can overcome some of this through the use of weights (weightx/weighty), but sometimes, you just need to provide a hard value for the minimum size as well...

Without knowing your exact needs (and you're going to need to make decisions about which components are more important), this is a rough example...

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LayoutTest {

    public static void main(String[] args) {
        new LayoutTest();
    }

    public LayoutTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JPanel greenPane = new JPanel() {

                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(275, 300);
                    }

                    @Override
                    public Dimension getMinimumSize() {
                        return getPreferredSize();
                    }

                    @Override
                    public Color getBackground() {
                        return Color.GREEN;
                    }

                };
                JPanel redPane = new JPanel() {

                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(300, 600);
                    }

                    @Override
                    public Dimension getMinimumSize() {
                        return getPreferredSize();
                    }

                    @Override
                    public Color getBackground() {
                        return Color.RED;
                    }

                };

                JPanel left = new JPanel(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.weightx = 1;
                gbc.weighty = 0.25;
                gbc.fill = GridBagConstraints.BOTH;

                left.add(greenPane, gbc);
                gbc.gridy++;
                gbc.weighty = 0.75;
                left.add(redPane, gbc);

                JPanel yellowPane = new JPanel() {

                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(600, 50);
                    }

                    @Override
                    public Dimension getMinimumSize() {
                        return getPreferredSize();
                    }

                    @Override
                    public Color getBackground() {
                        return Color.YELLOW;
                    }

                };

                JPanel grayPane = new JPanel() {

                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(400, 600);
                    }

                    @Override
                    public Dimension getMinimumSize() {
                        return getPreferredSize();
                    }

                    @Override
                    public Color getBackground() {
                        return Color.GRAY;
                    }

                };

                JPanel center = new JPanel(new GridBagLayout());
                gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.fill = GridBagConstraints.BOTH;
                gbc.weightx = 1;
                gbc.weighty = 1;
                center.add(grayPane, gbc);

                gbc.gridy++;
                gbc.weighty = 0;
                center.add(yellowPane, gbc);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(left, BorderLayout.WEST);
                frame.add(center);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}
2
On

Swing layout managers are quite decent, but unfortunetly they can make a lot of troubles. I think that the only layout managers that are actually usable are BorderLayout, GroupLayout and only in some cases GridBayLayout. In most cases I have found they are useless.

Why dont you try to use 3rd party layout managers? From my experience I can tell thal MigLayout is more than great. It is very flexible and have decent API. You will get desired layout composition in no time. I am using it in all desktop projects.