Search code examples
javaswinglayout-managergrouplayout

Problem with GroupLayout: components suddenly "burst" when resizing window


I had a Java assignment about a month ago, which was about building a GUI. I used GroupLayout to manage the position of the components. I ran into a problem where if I put a very long string of text into a JTextField and resize the outer window, the textfield suddenly "bursts".

I fixed the issue using GridBagLayout, but I wanted to come back to the original problem in hopes of getting a better understanding of GroupLayout.

Here's a SSCCE that demonstrates this problem. (I tried to minimize it as much as I can, I apologize if my example is too long.)

import javax.swing.*;
import java.awt.*;

public class Main extends JFrame {
    JTextField text1;
    JTextField text2;
    JPanel myPanel;

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(() -> new Main());
    }

    public Main() {
        super("Sussy Imposter");

        createComponents();
        setLayout();
        configureSettings();
    }

    public void createComponents() {
        text1 = new JTextField(20);
        text2 = new JTextField(20);
        text1.setMaximumSize(text1.getPreferredSize());
        text2.setMaximumSize(text2.getPreferredSize());

        myPanel = new JPanel();
        myPanel.setBackground(Color.CYAN);
        myPanel.setPreferredSize(new Dimension(100, 100));
    }

    public void setLayout() {
        Container c = getContentPane();
        GroupLayout groupLayout = new GroupLayout(c);
        c.setLayout(groupLayout);

        groupLayout.setAutoCreateGaps(true);
        groupLayout.setAutoCreateContainerGaps(true);
        groupLayout.setHorizontalGroup(
            groupLayout.createSequentialGroup()
            .addComponent(myPanel)
            .addGroup(groupLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addComponent(text1)
                .addComponent(text2))
        );
        groupLayout.setVerticalGroup(
            groupLayout.createParallelGroup()
                .addComponent(myPanel)
                .addGroup(groupLayout.createSequentialGroup()
                    .addComponent(text1)
                    .addComponent(text2))
        );
    }

    public void configureSettings() {
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
    }
}

Result of the SSCCE

When I copy-paste this text: Let me send you to space 🚀Space travel ASMR Roleplay 🚀(Eng)(Kor) | Roleplay, Storytime, Whitenoise into one of the textfields, and resize the outer window, the textfield "bursts".

enter image description here

I've set the maximum size of the textfields to their preferred sizes in createComponents(), so I don't understand why the size of the textfield exceeds its maximum size when I resize the window.

Can anyone explain why I'm getting this odd behavior?

EDIT: I've overrided the paint() method to see how the width of the textfield size change.

public void paint(Graphics g) {
    super.paint(g);
    System.out.printf("min: %d\n", text1.getMinimumSize().width);
    System.out.printf("pre: %d\n", text1.getPreferredSize().width);
    System.out.printf("max: %d\n", text1.getMaximumSize().width);
}

Output before resizing

min: 5
pre: 224
max: 224

Output after resizing

min: 569
pre: 224
max: 224

As @matt pointed out in the comments, this seems to happen because the minimumSize becomes very large. More notably, the minimumSize grows larger than the preferredSize and the maximumSize, which is very unexpected.


Solution

  • Edit: The behavior of the min size, growing after a resize, and becoming larger than the max size seems like a bug.
    Setting the min size explicitly is a workaround it:

    .addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
        .addComponent(text1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addComponent(text2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
    

    This sets the component min and max size to default size as explained in the documentation:

    To make a component fixed size (suppress resizing): group.addComponent(component, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)

    You can achieve the same behavior by setting the min as well as the max sizes:

    text1.setMinimumSize(text1.getPreferredSize());
    text1.setMaximumSize(text1.getPreferredSize());