Search code examples
javahtmlswingjlabelboxlayout

BoxLayout doesn't respect glue when JLabel contains HTML


I have a component I've written that uses BoxLayout to layout some JLabels horizontally, followed by glue (I'd like the JLabels' width to remain fixed). For example:

enter image description here

I need to add two lines of text to each JLabel, so I'm using a bit of HTML. As soon as I added the HTML, the BoxLayout stopped respecting the glue. I get something like:

enter image description here

I can get around this by specifying that the maximum size should be equal to the preferred size (specifying preferred size has no effect). Is this the correct approach? Is there some explanation for why glue seems to be ignored when there's HTML in my JLabels?

The MWE:

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

public class LabelBreak extends JFrame {

JPanel panel;

public LabelBreak() {
    setTitle("Frame");
    panel = new MyPanel();
    panel.setPreferredSize(new Dimension(500, 100));
    add(panel);
}

public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
        JFrame frame = new LabelBreak();
        frame.pack();
        frame.setVisible(true);
    });
}

private static class MyPanel extends JPanel {
    private MyPanel() {
        super();
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JPanel header = new JPanel();
        header.setLayout(new BoxLayout(header, BoxLayout.X_AXIS));
        //JLabel label = new JLabel("One");
        JLabel label = new JLabel("<html>One<br>is<br>the<br>loneliest<br>number</html>");
        label.setBorder(BorderFactory.createLineBorder(Color.RED, 2));
        header.add(label);
        label = new JLabel("Two");
        label.setBorder(BorderFactory.createLineBorder(Color.RED, 2));
        header.add(label);
        header.add(Box.createHorizontalGlue());
        this.add(header);
    }
}
}

Solution

  • Is there some explanation for why glue seems to be ignored when there's HTML in my JLabels?

    A BoxLayout will respect the maximum size (and minimum size) for components.

    For normal text the maximum size would be the preferred size of the component, so the glue works as expected.

    It looks like the calculation for the maximum size is different for HTML vs regular text.

    I can get around this by specifying that the maximum size should be equal to the preferred size

    Yes, this is a reasonable approach, but I would override the getMaximumSize() method to simply return the getPreferredSize() value.

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

    This way if you change the HTML it will still work.