-2

Here's a simple demo. The main class displays a frame with a GridLayoutManager-managed panel. The panel contains a stack of JLabels with long text strings

I expect the labels to shrink as I shrink the window, like so

However, they don't

import javax.swing.*;

public class FormDemoMain {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Form Demo");
        JPanel mainPanel = new LabelContainer().mainPanel;
        frame.setContentPane(mainPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;

public class LabelContainer {
    JPanel mainPanel;
    private JLabel labelOne;
    private JLabel labelTwo;
    private JLabel labelThree;

    LabelContainer() {
        // you may replace StringUtils.repeat("str", 20) with "str".repeat(20) if your JDK is 11+
        String longText = StringUtils.repeat("long ", 20) + "text";
        labelOne.setText("Label One: " + longText);
        labelTwo.setText("Label Two: " + longText);
        labelThree.setText("Label Three: " + longText);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="stretchableLabel.form.LabelContainer">
  <grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="10" vgap="10">
    <margin top="0" left="0" bottom="0" right="0"/>
    <constraints>
      <xy x="20" y="20" width="500" height="400"/>
    </constraints>
    <properties>
      <background color="-7563106"/>
    </properties>
    <border type="none"/>
    <children>
      <component id="cadde" class="javax.swing.JLabel" binding="labelOne">
        <constraints>
          <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <background color="-11841453"/>
          <foreground color="-1"/>
          <opaque value="true"/>
          <text value="Label"/>
        </properties>
      </component>
      <component id="36e79" class="javax.swing.JLabel" binding="labelTwo">
        <constraints>
          <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <background color="-11841453"/>
          <foreground color="-1"/>
          <opaque value="true"/>
          <text value="Label"/>
        </properties>
      </component>
      <component id="744ac" class="javax.swing.JLabel" binding="labelThree">
        <constraints>
          <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
        </constraints>
        <properties>
          <autoscrolls value="false"/>
          <background color="-11841453"/>
          <foreground color="-1"/>
          <opaque value="true"/>
          <text value="Label"/>
        </properties>
      </component>
    </children>
  </grid>
</form>

enter image description here

The problem is not reproduced with the OOB GridLayout. Note the ellipses

import org.apache.commons.lang3.StringUtils;

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

public class GridLayoutDemo {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Grid Layout Demo");
        JPanel labelPanel = new JPanel();
        LayoutManager layout = new GridLayout(0,1,10,10);
        labelPanel.setLayout(layout);
        labelPanel.setBackground(Color.LIGHT_GRAY);
        String shortText = "Short label text";
        JLabel labelOne = new JLabel(shortText);
        labelOne.setOpaque(true);
        labelOne.setBackground(Color.DARK_GRAY);
        labelOne.setForeground(Color.WHITE);
        JLabel labelTwo = new JLabel(shortText);
        labelTwo.setOpaque(true);
        labelTwo.setBackground(Color.DARK_GRAY);
        labelTwo.setForeground(Color.WHITE);
        labelPanel.add(labelOne);
        labelPanel.add(labelTwo);
        frame.add(labelPanel);
        JButton makeShortButton = new JButton("Make short");
        makeShortButton.addActionListener(e -> {
            labelOne.setText("Label One: " + shortText);
            labelTwo.setText("Label Two: " + shortText);
            frame.pack();
        });
        JButton makeLongButton = new JButton("Make long");
        String longText = "Long" + StringUtils.repeat(" long", 30) + " label text";
        makeLongButton.addActionListener(e -> {
            labelOne.setText("Label One: " + longText);
            labelTwo.setText("Label Two: " + longText);
            frame.pack();
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(makeShortButton);
        buttonPanel.add(makeLongButton);
        frame.add(buttonPanel, BorderLayout.SOUTH);
        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

enter image description here

The GUI Designer interface doesn't allow a regular GridLayout, only JetBrains' own com.intellij.uiDesigner.core.GridLayoutManager

enter image description here

What complicates things further, I can't debug it. I can't even open the source file of that layout manager in the IDE

One possible way out is GridBagLayout which is supported by GUI Designer. However, the layout manager either proved to be too complex to get it right or doesn't support it at all. Here's my attempt (without GUI forms)

import org.apache.commons.lang3.StringUtils;

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

public class GridBagLayoutManagerDemo {
    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagLayout Demo");
        JLabel labelOne = new JLabel("first" + StringUtils.repeat(" long label", 20));
        labelOne.setOpaque(true);
        labelOne.setBackground(Color.DARK_GRAY);
        labelOne.setForeground(Color.WHITE);
        JLabel labelTwo = new JLabel("second" + StringUtils.repeat(" long label", 20));
        labelTwo.setOpaque(true);
        labelTwo.setBackground(Color.DARK_GRAY);
        labelTwo.setForeground(Color.WHITE);
        JPanel labelPanel = new JPanel();
        labelPanel.setBackground(Color.LIGHT_GRAY);
        GridBagLayout layout = new GridBagLayout();

        labelPanel.setLayout(layout);
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.gridy = 0;
        labelPanel.add(labelOne, constraints);
        constraints.gridy = 1;
        labelPanel.add(labelTwo, constraints);
        frame.add(labelPanel, BorderLayout.CENTER);
        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

It starts to shrink at first...

enter image description here

...but then abandons that idea as I shrink the window further

enter image description here

I know the drawbacks of GUI Designer only too well. But we're so coupled with it, we can't ever get uncoupled. The ability to see the approximate visual rendering of your components right in the source code is so appealing

How can I make a stack of labels shrink as the containing window is shrinked with GUI Designer forms?

7
  • (1-) Why are you still using StringUtils. The point of an minimal reproducible example is to make it easy for us to test, not to make it easy for you to write. How hard is it for you to create a string by doing String long = "this is a long text string to show the problem with my layout managers".: Given that you continually ask questions, instead of spending time answering questions you should listen to advice provide on how to create a better MRE for all people.
    – camickr
    Commented Jul 10 at 14:32
  • @camickr I addressed that criticism by adding a comment on how you can easily replace it in newer JDKs (11+)
    – demavi
    Commented Jul 10 at 14:35
  • That is NOT The point. We should be able to copy/paste/compile/test. Again if you want multiple people to look at the question, why should each individual need to make the change when you can do it once yourself?
    – camickr
    Commented Jul 10 at 14:37
  • @camickr besides, Apache Commons is nothing fancy. Everyone has it in their classpath (directly or indirectly)
    – demavi
    Commented Jul 10 at 14:40
  • 1
    So the point of the MRE is to completely simplify the code. Until a problem is solved you don't know what the problem is or what statement may cause the problem. Remember you are NOT the only person we are helping. If we have to spend time making changes for every question that leaves us with less time to help others.
    – camickr
    Commented Jul 10 at 14:50

1 Answer 1

2

Referring to the standard GridBagLayout, its documentation doesn’t say anything about shrinking. But we get on the right track when we consider the scenario of having less than the preferred or minimum size as “distributing negative ‘extra space’”:

GridBagConstraints.weightx

Specifies how to distribute extra horizontal space.

The grid bag layout manager calculates the weight of a column to be the maximum weightx of all the components in a column. If the resulting layout is smaller horizontally than the area it needs to fill, the extra space is distributed to each column in proportion to its weight. A column that has a weight of zero receives no extra space.

So, the solution looks like

public class GridBagLayoutManagerDemo {
    public static void main(String[] args) {
        JFrame frame = new JFrame("GridBagLayout Demo");
        JLabel labelOne = new JLabel("first" + " long label".repeat(20));
        labelOne.setOpaque(true);
        labelOne.setBackground(Color.DARK_GRAY);
        labelOne.setForeground(Color.WHITE);
        labelOne.setFont(new Font(Font.DIALOG, 0, 12)); // https://stackoverflow.com/a/78725796/2711488
        JLabel labelTwo = new JLabel("second" + " long label".repeat(20));
        labelTwo.setOpaque(true);
        labelTwo.setBackground(Color.DARK_GRAY);
        labelTwo.setForeground(Color.WHITE);
        labelTwo.setFont(new Font(Font.DIALOG, 0, 12)); // https://stackoverflow.com/a/78725796/2711488
        JPanel labelPanel = new JPanel();
        labelPanel.setBackground(Color.LIGHT_GRAY);
        GridBagLayout layout = new GridBagLayout();

        labelPanel.setLayout(layout);
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.gridy = 0;
        constraints.weightx = 1;
        labelPanel.add(labelOne, constraints);
        constraints.gridy = 1;
        labelPanel.add(labelTwo, constraints);
        frame.add(labelPanel, BorderLayout.CENTER);
        frame.pack();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Note that in case of having more space than needed, this solution only expands the virtual cells the components live in. To let the components take the extra space of the larger cell, the fill property must be set appropriately.

Not the answer you're looking for? Browse other questions tagged or ask your own question.