FaithReaper FaithReaper - 4 months ago 53
Java Question

Swing MigLayout cannot grow fill column to fill container length

I am using

MigLayout
for a very long window.

enter image description here
and I wish to "push" the second and fourth column to fill all the length of the whole window, but I cannot achieve it. There's no
push
option in column constraint, only
grow
and
fill
.

Here's a SCCEE, as someone once suggested, whose name I already forgot:

package com.WindThunderStudio.MigLayoutTest;

import java.awt.Cursor;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class MigLayoutTest extends JFrame{
private JFrame mainFrame;
private JPanel panel;

private JLabel lblResumenAuto;
private JLabel lblResumenAutoResult;
private JLabel lblResumenRazonSocial;
private JLabel lblResumenRazonSocialResult;
private JLabel lblResumenPeriodo;
private JLabel lblResumenPeriodoResult;
private JLabel lblResumenFechaHora;
private JLabel lblResumenFechaHoraResult;

public MigLayoutTest(){
run();
}

public void run(){
mainFrame = new JFrame();
mainFrame.setBounds(0, 0, 1250, 500);
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

JPanel p = new JPanel();
p.setSize(mainFrame.getSize());

p.setLayout(new MigLayout("fill","[max!, grow]","[50:20:30]10[100::]10[20::]10[50!]10[20!]"));
mainFrame.setContentPane(p);

panel = new JPanel();
panel.setLayout(new MigLayout("fillx", "[left, 15%]10[left, grow, 35%]10[left, 15%]10[left, grow, 35%]", "[center]10[center]"));

lblResumenAuto = new JLabel("MY LABEL 1111111111111");
lblResumenAutoResult = new JLabel("1111111111111111111111");

panel.add(lblResumenAuto);
panel.add(lblResumenAutoResult);

lblResumenRazonSocial = new JLabel("MY LABEL 2222222222");
lblResumenRazonSocialResult = new JLabel("2222222222222222222222");

panel.add(lblResumenRazonSocial);
panel.add(lblResumenRazonSocialResult,"wrap");

lblResumenPeriodo = new JLabel("MY LABEL 33333333333333");
lblResumenPeriodoResult = new JLabel("3333333333333333333333333333333333333333333333333333333");

panel.add(lblResumenPeriodo);
panel.add(lblResumenPeriodoResult);
//poner el texto como html puede tener otra linea, porque es muy largo
lblResumenFechaHora = new JLabel("<html>MY LABEL <br /> 4444444444444444</html>");
lblResumenFechaHoraResult = new JLabel("4444444444444444444444444");

panel.add(lblResumenFechaHora);
panel.add(lblResumenFechaHoraResult);

p.add(panel,"cell 0 0");

getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
setBounds(0, 0, 1250, 500);
getContentPane().add(mainFrame.getContentPane());

pack();
setVisible(true);
setLocationRelativeTo(null);
setResizable(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
MigLayoutTest test = new MigLayoutTest();

}
});
}
}


If you run the code, you can note that the columns' width increases as its containing text's length changes. But it never fills the whole width of its container.

What's desirable, is to fix the column 0 and 2 by
15%
of the whole width, and let column
1
and
3
to ocupy the rest,
35%
, with the first two columns occupying the 50% size of the whole width.

Am I missing something here? I don't want to specify the width of every column, setting
pre:min:max
, because it is bad practice, as suggested by this post, which gets lots of vote up.

panel.setLayout(new MigLayout("fillx",
"[left, 15%]10[left, grow, 35%]10[left, 15%]10[left, grow, 35%]",
"[center]10[center]"));


But, if I set
pref:min:max
, it can fill the whole width.

Answer

First the code, then explanation. Try this:

import java.awt.Cursor;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class MigLayoutTest extends JFrame {
  private JPanel panel;

  private JLabel lblResumenAuto;
  private JLabel lblResumenAutoResult;
  private JLabel lblResumenRazonSocial;
  private JLabel lblResumenRazonSocialResult;
  private JLabel lblResumenPeriodo;
  private JLabel lblResumenPeriodoResult;
  private JLabel lblResumenFechaHora;
  private JLabel lblResumenFechaHoraResult;

  public MigLayoutTest() {
    run();
  }

  public void run() {
    panel = new JPanel();
    panel.setLayout(new MigLayout("debug, fill",
        "[left, 15%]10[left, 35%]10[left, 15%]10[left, 35%]", "[center]10[center]"));

    lblResumenAuto = new JLabel("MY LABEL 1111111111111");
    lblResumenAutoResult = new JLabel("1111111111111111111111");

    panel.add(lblResumenAuto, "sg label");
    panel.add(lblResumenAutoResult, "sg value");

    lblResumenRazonSocial = new JLabel("MY LABEL 2222222222");
    lblResumenRazonSocialResult = new JLabel("2222222222222222222222");

    panel.add(lblResumenRazonSocial, "sg label");
    panel.add(lblResumenRazonSocialResult, "sg value, wrap");

    lblResumenPeriodo = new JLabel("MY LABEL 33333333333333");
    lblResumenPeriodoResult = new JLabel("3333333333333333333333333333333333333333333333333333333");

    panel.add(lblResumenPeriodo, "sg label");
    panel.add(lblResumenPeriodoResult, "sg value");
    // poner el texto como html puede tener otra linea, porque es muy largo
    lblResumenFechaHora = new JLabel("<html>MY LABEL <br /> 4444444444444444</html>");
    lblResumenFechaHoraResult = new JLabel("4444444444444444444444444");

    panel.add(lblResumenFechaHora, "sg label");
    panel.add(lblResumenFechaHoraResult, "sg value");

    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    getContentPane().add(panel);

    pack();
    setVisible(true);
    setLocationRelativeTo(null);
    setResizable(true);
  }

  public static void main(String[] args) {
    MigLayoutTest test = new MigLayoutTest();
  }

}

The explanation of my changes:

Now except for simplifying the code and layout I used “debug” within the layout constraints to see what actually happens to the layout. I suggest using it anytime things go wrong with the layout - it makes MigLayout draw the borders of components and cells, thus visualizing potential problems.

I removed the unnecessary mainframe and p - if you really need it for a nested layout try to add it once you have solved the inner layout to your liking.

As to p and panel - it might be that you need here two different layouts, one nested in another, but this is the actual source of your problem. p had also its own grid layout, with

p.add(panel,"cell 0 0");

you put panel in the top left cell of the p - this is why panel was not distributed over the whole window but sat in the upper left corner.

As you see without p it positions nicely in the middle of the screen without any constant size, still showing all components, but more importantly it has 50% of the window size for the first and 50% for the last two columns. This was achieved by giving the components a “sizegroup”:

Gives the component a size group name. All components that share a size group name will get the same BoundSize (min/preferred/max). It is used to make sure that all components in the same size group gets the same min/preferred/max size which is that of the largest component in the group. An empty name "" can be used.

And it also resizes like it should!

The nested layout might also had been the root of another problem – don’t know if you didn’t notice it or it just didn’t show up on your machine, but if I tried to resize your window the panel got wider and wider (never narrower) even if I shrunk the window. At some point it got wider than the window itself and even then growed further on each resize.

Next - setting the dimensions to a constant value didn’t make sense, since after pack the layout manager starts sizing everything based on preferred sizes of the window and its content. Besides, you never know which size is your users’ screen, so any constant size could be equally bad if effectively used. Better to drive the size through the content and available runtime environment. With your code on my machine it took all available horizontal space of my two screens (2 x 1280) and did’t look pretty.

I also think that you do not need to start the frame using EventQueue.invokeLater, just create a MigLayoutTest and that’s it.