6244

Swing MigLayout cannot grow fill column to fill container length

I am using MigLayout for a very long window.

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/zP0I9.jpg" alt="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.

Answer1:

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.

<strong>EDIT after OP's own answer</strong>

Setting the size using setBounds(0, 0, 1250, 500) before pack is not working correctly (by this I mean making the window be that size). Even in the screenshot below OP's own answer it is not 500px high. Here is what I get on Windows 7 running JDK 1.8.0_91:

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/Sh2wK.png" alt="Screenshot">

The size of my screen is 1280 x 1024, the size of the programm's window is 914 x 301.

I'd suggest using one of the following:

To set it to the constant size of 1250 x 500 px move the setSize between pack and setVisible:

... pack(); setSize(1250, 500);

I'd use setSize, setBounds doesn't make sense, since by calling setLocationRelativeTo(null) you centering the programm's window on the screen anyway, so the origin is being dismissed immediately.

To maximize horizontally and let the height be 500 px set main window's preferred size before pack:

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setPreferredSize(new Dimension(screenSize.width, 500));

And to maximize horizontally and let the preferred height as it was originally:

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); setPreferredSize(new Dimension(screenSize.width, getPreferredSize().height));

Of course you can make the window 1250 x 500 big by setting its preferred size instead of using setSize, too.

The resize problem is not so big now, but it's still there - make the window wider, than narrow it just a little bit. You'll notice that the panel gets wider even if the window got narrowed. The problem is that panel component doesn't get big enough to fill the one column of p initially (BTW you can add the 'debug' flag to each MigLayout, also that of the panel - it will then outline all of the inner components as well).

To make it fill the parent container add it like this:

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

Now it is the full width of p from the very beginning and resizing works as expected.

Regarding starting the JFrame using invokeLater - we start our main windows usually without it and had never had problems, since there were no interactions with Swing until the first frame was visible, yet I have just noticed that it is regarded to be the best practise - even in Oracle's tutorials. It looks like I had learned something here, too :-).

<strong>Comparision of the frame's window with and without adding with "grow"</strong>

Test scenario: start the application and resize it to be wider.

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/cMqvc.png" alt="Using exactly the code in OP's own answer">

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/tysiZ.png" alt="Using <code>p.add(panel,"cell 0 0, grow");</code>">

As you see in the first screenshot the component size is smaller than the column width - it looks like the component were lying behind the column size while resizing. On the second screenshot the component width remains the same as the column width at all times. As I said previously the reason might be the Java and/or operating system combination, I don't know. But obviously it behaves differently and on my machine less than optimal.

Answer2:

Thanks to @Tomasz Stanczak, I have solved it finally. However, I found part of what he said is relevant, and others are not. For future readers who may see this, I have to made it clearer.

The final working code is:

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 MigLayoutMySCCEE 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 MigLayoutMySCCEE(){ run(); } public void run(){ JPanel p = new JPanel(); p.setLayout(new MigLayout("debug, fill","[grow]","[50:20:30]10[100::]10[20::]10[50!]10[20!]")); 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"); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); setBounds(0, 0, 1250, 500); getContentPane().add(p); pack(); setVisible(true); setLocationRelativeTo(null); setResizable(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { MigLayoutMySCCEE test = new MigLayoutMySCCEE(); } }); } }

And the window looks like:

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/xDqRI.png" alt="enter image description here">

Some notes:

<ol> <li>

The debug trick is very useful and urges me to read DOC again. I wish it can gain more attention and importance in the Quick Start page, however.

</li> <li>

The unnecessary nesting is a problem and Tomasz make me to review the hierarchy, great! I changed the nesting part to make it clearer. But it's irrelevant.

</li> <li>

The sizeGroup part is great idea and I decide to use it in future development as much as possible, but it's irrelevant to my case. I solved it without using it.

</li> <li>

I have found the wider-and-wider problem after Tomasz's tip, but it is due to [max!] combined with adding the panel to the first cell of grid layout, not frame/panel nesting. I removed [max!] and changed it to [grow] and the width is not expanding anymore. I didn't touch the p.add(panel, "cell 0 0") part. As observed and by definition,

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

</li> </ol>

the first line of the panel has only one column, if I understand well.

<strong>EDIT after Tomasz's edit</strong>

I surely have learned more than you did :) I tried to get rid of setBounds() part and to change add(panel, "cell 0 0") to add(panel, "grow"), but I cannot see much difference, am I missing something here? <strong>Yet "grow" is almost always the better choice and desirable.</strong>

Here's 2 GIFs showing what I got: (by ScreenToGif, a light-weighted but powerful tool, especially useful for showcase)

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/B5hjS.gif" alt="enter image description here">

<img src=https://www.e-learn.cn/content/wangluowenzhang/"https://i.stack.imgur.com/UQGjw.gif" alt="enter image description here">

Recommend

  • MeteorJs putting Cordova barcode scanner inside a fixed div
  • How to align Custom cells to Right Detail and Basic cells?
  • Allocating a 2D contiguous array within a function
  • Refactoring advice: maps to POJOs
  • Is there a way to choose which files are displayed to the user via the standard OPENFILE dialogs?
  • Setting WPF Window Background to Resource Dictionary Brush User Setting
  • Display validation errors inside
  • WPF version of .ScaleControl?
  • Floated image with variable width and heading with background image
  • bad substitution shell- trying to use variable as name of array
  • Extract zip entries to another Zip file
  • C# program and C++ DLL compiled for 32-bit system crash on 64-bit system
  • Authentication in Play! and RestEasy
  • D3 get axis values on zoom event
  • Using a canvas object in a thread to do simple animations - Java
  • Assign variable to the value in HTML
  • jQuery ready not fired after rails link_to is clicked
  • GridView breaks while scrolling
  • WPF - CanExecute dosn't fire when raising Commands from a UserControl
  • How to change the font size of a single index for UISegmentedControl?
  • Time complexity of a program which involves multiple variables
  • Custom validator control occupying space even though display set to dynamic
  • JSON response opens as a file, but I can't access it with JavaScript
  • Bad request using file_get_contents for PUT request in PHP
  • Atlas images wrong size on iPad iOS 9
  • Change multiple background-images with jQuery
  • Android screen density dpi vs ppi
  • DirectX11 ClearRenderTargetViewback with transparent buffer?
  • 'TypeError' while using NSGA2 to solve Multi-objective prob. from pyopt-sparse in OpenMDAO
  • Change an a tag attribute in JavaScript based on screen width
  • Matrix multiplication with MKL
  • Android Studio and gradle
  • SQL merge duplicate rows and join values that are different
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • Memory offsets in inline assembly
  • File not found error Google Drive API
  • Linking SubReports Without LinkChild/LinkMaster
  • apache spark aggregate function using min value
  • How can I remove ASP.NET Designer.cs files?
  • Is it possible to post an object from jquery to bottle.py?