Search code examples
javamiglayout

Why do I need to use "X:X" in the MigLayout in order to center components over several panels?


I've tried to center some components over several panels with the MigLayout (see the example here). It suddenly worked, when I split the page into percentages that are the same in all panels.

BUT I had to use the parameter "0:0" in front of each grow and I dont understand what is happening exactly.

I went to the MigLayout CheatSheet-Page and the QuickStart-guide but only could find parameters with values > 0

The format is "min:preferred:max", however there are shorter versions since for instance it is seldom needed to specify the maximum size. A single value (E.g. "10") sets only the preferred size and is exactly the same as "null:10:null" and ":10:" and "n:10:n".

Two values (E.g. "10:20") means minimum and preferred size and is exactly the same as "10:20:null" and "10:20:" and "10:20:n"

But it does not explain what happens, when you use the 0 as a parameter, or why you need to use X:X or X:Yat all and not for example X:Y:Z or X:X:X?

So why do I need to use X:X here to center my components?


Solution

  • The bit that matters here is the preferred size. In your other question, you said you used the following code to get it to work.

    locationPanel.setLayout(new MigLayout("gap rel 2", "[0:0, grow 60, center][grow 40, left]"));
    usagePanel.setLayout(new MigLayout("gap rel 2", "[0:0, grow 60, center][grow 40, left]"));
    structuralAspectsPanel.setLayout(new MigLayout("gap rel 2", "[0:0, grow 60, center][grow 40, left]"));
    

    This would have also worked if you had wrote

    locationPanel.setLayout(new MigLayout("gap rel 2", "[:0:, grow, center][grow, left]"));
    usagePanel.setLayout(new MigLayout("gap rel 2", "[:0:, grow, center][grow, left]"));
    structuralAspectsPanel.setLayout(new MigLayout("gap rel 2", "[:0:, grow, center][grow, left]"));
    //Obviously you could use any number not just 0
    

    Options you could use are (Where X <= Y <= Z)

    X:Y:Z
    X:Y:
    :Y:Z
    :Y:
    :Y
    

    So why does it do this?
    It does this because the columns grow at the same rate and when you set the preferred size of the first column in all three panels you are setting the initial size as MigLayout sets the initial column size to the preferred size.

    In essensce you set columns to the same size and they grow at the same rate, so they remain equal sizes to each other. Hence they stay in line.

    Working Example
    Uses :Y where Y is determined by Font Metrics

    import java.awt.*;
    import javax.swing.*;
    import net.miginfocom.swing.MigLayout;
    
    public class MigLay extends JFrame {
    
        private MigLay() {
            super("Button Layout");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLayout(new MigLayout("wrap", //Layout Constraints
            "grow, fill", //Column Constraints
            "grow, fill")); //Row Constraints
            createPanels();
            pack();
            setMinimumSize(getSize()); //Sets minimum size to the preferred size. Remove or change this line if you do not want that to happen
            setVisible(true);
        }
    
        private void createPanels() {
    
            JPanel locationPanel = new JPanel();
            JPanel usagePanel = new JPanel();
            JPanel structuralAspectsPanel = new JPanel();
    
            //JLabels for font metrics
            JLabel one = new JLabel("This is the first of all labels");
            JLabel two = new JLabel("Second Label");
            JLabel three = new JLabel("This Label is fairly large and long and pushes the text around");
            JLabel four = new JLabel("A label in the usage panel");
            JLabel five = new JLabel("And another one and another one and another one");
    
            //Font Metrics
            FontMetrics metrics = three.getFontMetrics(three.getFont()); //Take longest label manually or dynamically (You will have to add that code)
            int width = metrics.stringWidth(three.getText());
    
            locationPanel.setLayout(new MigLayout("gap rel 2", "[:" + width + ", grow, center][grow, left]"));
            locationPanel.setBorder(BorderFactory.createTitledBorder("Location"));
    
            usagePanel.setLayout(new MigLayout("gap rel 2", "[:" + width + ", grow, center][grow, left]"));
            usagePanel.setBorder(BorderFactory.createTitledBorder("Usage"));
    
            locationPanel.add(one);
            locationPanel.add(new JCheckBox("Checkbox with Label"), "wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JSeparator(), "growx, span");
            locationPanel.add(two);
            locationPanel.add(new JCheckBox("Checkbox with Label"), "wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JSeparator(), "growx, span");
            locationPanel.add(three);
            locationPanel.add(new JCheckBox("Checkbox with Label"), "wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            locationPanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
    
            usagePanel.add(four);
            usagePanel.add(new JCheckBox("Checkbox with Label"), "wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JSeparator(), "growx, span");
            usagePanel.add(five);
            usagePanel.add(new JCheckBox("Checkbox with Label"), "wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
            usagePanel.add(new JCheckBox("Checkbox with Label"), "skip, wrap");
    
            getContentPane().add(locationPanel);
            getContentPane().add(usagePanel);
        }
    
        public static void main(String[] args) {
            new MigLay();
        }
    }