Table of Contents
Overview
If you are working on swing desktop app, MigLayout is a great library to help you layout your app quickly.
MiGLayout revolves around flexibility and simplicity while offering powerful features for fine-grained layout control. Here are the main concepts to understand when working with MiGLayout.
1. Components and Cells
- Each component in MiGLayout is placed into a cell within a grid.
- The grid dynamically adjusts based on the layout constraints, column/row constraints, and the components inside it.
- Components can span multiple cells, be aligned, resized, or stretched to fit the space.
2. Layout Constraints
- Purpose: Define global rules for the entire layout.
- Examples of global behaviors include:
- Wrapping components after a certain number (
wrap
). - Adding padding around the layout (
insets
). - Changing the flow of components (horizontal/vertical).
- Wrapping components after a certain number (
- Syntax is provided in the first argument of
new MigLayout()
.
Here are some examples
Wrap after x columns
class WrapExample { public static void main(String[] args) { JFrame frame = new JFrame("Wrap Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(new MigLayout("wrap 3")); // Wrap after 3 components for (int i = 1; i <= 10; i++) { panel.add(new JButton("Button " + i)); } frame.add(panel); frame.pack(); frame.setVisible(true); } }
Padding with insets
class InsetsExample { public static void main(String[] args) { JFrame frame = new JFrame("Insets Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add 10px padding on all sides JPanel panel = new JPanel(new MigLayout("wrap 2, insets 100 10 100 10")); panel.add(new JLabel("Label 1:")); panel.add(new JTextField(10)); panel.add(new JLabel("Label 2:")); panel.add(new JTextField(10)); frame.add(panel); frame.pack(); frame.setVisible(true); } }
Changing the Flow of Components
class FlowyExample { public static void main(String[] args) { JFrame frame = new JFrame("Flowy Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Change flow direction to vertical JPanel panel = new JPanel(new MigLayout("flowy, insets 5")); panel.add(new JLabel("Label 1")); panel.add(new JTextField(15)); panel.add(new JLabel("Label 2")); panel.add(new JTextField(15)); panel.add(new JButton("Submit")); frame.add(panel); frame.pack(); frame.setVisible(true); } }
Combined example
class CombinedExample { public static void main(String[] args) { JFrame frame = new JFrame("Combined Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Combine constraints: wrap, insets, and fill JPanel panel = new JPanel(new MigLayout("wrap 2, insets 15, fillx")); panel.add(new JLabel("First Name:")); panel.add(new JTextField(15), "growx"); panel.add(new JLabel("Last Name:")); panel.add(new JTextField(15), "growx"); panel.add(new JLabel("Email:")); panel.add(new JTextField(15), "growx"); panel.add(new JButton("Submit"), "span 2, align center"); frame.add(panel); frame.pack(); frame.setVisible(true); } }
Wonder what growx
, fillx
are? They will be explained in the next post
3. Column and Row Constraints
- Purpose: Define behavior for specific columns and rows.
- Examples of customization:
- Specifying fixed or variable sizes.
- Allowing columns/rows to grow, shrink, or fill available space.
- Syntax is provided in the second and third arguments of
new MigLayout()
.
Let’s have a look at some examples:
Specifying Fixed Column Width ([100px])
class FixedColumnExample { public static void main(String[] args) { JFrame frame = new JFrame("Fixed Column Width"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // First column is fixed at 100px, second is default JPanel panel = new JPanel(new MigLayout("", "[100px][grow]", "")); panel.add(new JLabel("Fixed Width:"), "align right"); panel.add(new JTextField(15), "growx"); // Second column grows frame.add(panel); frame.pack(); frame.setVisible(true); } }
The first column always stays 100px wide, while the second column grows if space is available.
Allowing a Column to Grow ([grow])
class GrowableColumns{ public static void main(String[] args) { JFrame frame = new JFrame("Growable Columns"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // First column grows twice as much as the second JPanel panel = new JPanel(new MigLayout("", "[grow][grow]", "")); panel.add(new JButton("Button 1"), "growx"); panel.add(new JButton("Button 2"), "growx"); frame.add(panel); frame.setSize(400, 100); // Set an initial size larger than needed frame.setVisible(true); } }
The grow option dictates how is the division of extra space is made. Consider the following example:
class GrowableColumnsUnequalGrow { public static void main(String[] args) { JFrame frame = new JFrame("Extra Space Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // First column grows twice as much as the second JPanel panel = new JPanel(new MigLayout("", "[grow 2][grow 1]", "")); panel.add(new JButton("Button 1"), "growx"); panel.add(new JButton("Button 2"), "growx"); frame.add(panel); frame.setSize(400, 100); // Set an initial size larger than needed frame.setVisible(true); } }
Setting Size Range ([min:pref:max])
class SizeRangeExample { public static void main(String[] args) { JFrame frame = new JFrame("Column Size Range"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // First column: size range 50px (min) to 200px (max), preferred is 100px JPanel panel = new JPanel(new MigLayout("debug", "[50:100:200][grow]", "")); panel.add(new JLabel("A very big column"), "align right"); panel.add(new JTextField(15), "growx"); frame.add(panel); frame.pack(); frame.setVisible(true); } }
The first column maintains a size between 50px and 200px but defaults to 100px if space allows.
4. Component Constraints
- Purpose: Define rules for each individual component.
- Examples of component-specific behavior:
- Spanning across multiple cells.
- Adjusting alignment within the cell.
- Controlling growth and shrinking behavior.
- Syntax is provided when adding a component (
add(component, "constraints")
).
Here is an example to demonstrate components constraints:
class AlignmentCombinedExample { public static void main(String[] args) { JFrame frame = new JFrame("Combined Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(new MigLayout("debug, wrap 2", "[][grow][]", "")); panel.add(new JLabel("Name:"), "alignx right"); panel.add(new JTextField(15), "growx"); panel.add(new JLabel("Address:"), "alignx right"); panel.add(new JTextField(15), "span 2, growx"); // Spanning 2 columns panel.add(new JLabel("Notes:"), "alignx right"); panel.add(new JTextArea(3, 20), "span 2, growx"); // Spanning and growing frame.add(panel); frame.setSize(500, 200); // Set an initial size larger than preferred frame.setVisible(true); } }
In this example, all labels are aligned right so you can see that they are closer to the text boxes.
Also, the first textbox doesn’t have a span 2 so I just span 1 column.
Since the layout wraps at 2nd column, the 3rd column is quite insignificant. However, you can still see the first textbox is a bit shorter than the second and the third.
5. Dynamic Growth and Shrink
- MiGLayout can dynamically resize components to make the best use of available space.
- Components, columns, and rows can be marked as:
- Growable: Expands to take up extra space (
grow
). - Shrinkable: Shrinks to fit when space is limited (
shrink
).
- Growable: Expands to take up extra space (
Examples:
- Adding
growx
orgrowy
to a component makes it expand in that direction. - Adding
[grow]
to a column allows it to expand.
Component Growth with growx
class ComponentGrowthExample { public static void main(String[] args) { JFrame frame = new JFrame("Component Growth Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Layout with two columns JPanel panel = new JPanel(new MigLayout("wrap 2", "[][grow]", "")); panel.add(new JLabel("Name:")); panel.add(new JTextField(15), "growx"); // TextField grows horizontally frame.add(panel); frame.setSize(400, 100); // Initial size to see growth frame.setVisible(true); } }
The text box component resize with the window as I resize it:
The JTextField
grows horizontally when you resize the window, taking up available space in its column.
Growth and Shrink
class GrowthAndShrinkExample { public static void main(String[] args) { JFrame frame = new JFrame("Growth and Shrink Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Layout with three columns: first fixed, second and third grow/shrink JPanel panel = new JPanel(new MigLayout("wrap 3", "[][grow, shrink 50][grow, shrink 30]", "")); panel.add(new JLabel("Fixed Column:")); panel.add(new JTextField(10), "growx"); // Grows and shrinks with the column panel.add(new JButton("Grow & Shrink"), "growx"); // Grows and shrinks with the column frame.add(panel); frame.setSize(600, 100); // Initial size to observe behavior frame.setVisible(true); } }
Shrink provides finer control over how components or columns shrink, useful in more complex layouts. In the example above, shrink
comes with a number signifying the aggressiveness of the shrink. The higher the number, the more possible that the component will shrink:
6. Wrapping and Gaps
- MiGLayout automatically handles wrapping and spacing between components:
- Wrapping:
- Global:
wrap n
in layout constraints wraps aftern
components. - Local:
wrap
in a component’s constraints forces wrapping after that component.
- Global:
- Gaps:
- Global:
gap x y
defines default gaps between components. - Local:
gap x1 x2
defines custom gaps around a specific component.
- Global:
- Wrapping:
Wrapping Components Globally (wrap n)
The wrap n layout constraint wraps to a new row after n components. java Copy code
class GlobalWrapExample { public static void main(String[] args) { JFrame frame = new JFrame("Global Wrap Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Wrap after 3 components JPanel panel = new JPanel(new MigLayout("wrap 3")); for (int i = 1; i <= 9; i++) { panel.add(new JButton("Button " + i)); } frame.add(panel); frame.pack(); frame.setVisible(true); } }
Forcing Wrapping Locally (wrap)
You can force wrapping after a specific component using the wrap constraint. java Copy code
class LocalWrapExample { public static void main(String[] args) { JFrame frame = new JFrame("Local Wrap Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(new MigLayout()); panel.add(new JButton("Button 1")); panel.add(new JButton("Button 2"), "wrap"); // Force wrapping after this button panel.add(new JButton("Button 3")); panel.add(new JButton("Button 4"), "wrap"); // Force wrapping again panel.add(new JButton("Button 5")); frame.add(panel); frame.pack(); frame.setVisible(true); } }
Global Gaps (gap x y)
Global gaps set default horizontal (x) and vertical (y) spacing between components. java Copy code
class GlobalGapExample { public static void main(String[] args) { JFrame frame = new JFrame("Global Gap Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Set global gaps: 10px horizontal, 15px vertical JPanel panel = new JPanel(new MigLayout("gap 10 15")); for (int i = 1; i <= 6; i++) { panel.add(new JButton("Button " + i)); } frame.add(panel); frame.pack(); frame.setVisible(true); } }
Increasing the x gap JPanel panel = new JPanel(new MigLayout("gap 90 15"));
7. Debugging
- The
debug
constraint is invaluable for understanding how the grid is structured. - When enabled, it draws outlines around all cells and components, helping you visualize their positioning and size.
8. Intuitive Sizing
- MiGLayout intelligently sizes components based on:
- Their preferred size (defined by the component).
- Available space in the container.
- Constraints like
min
,pref
, ormax
sizes.
9. Docking
- Components can be docked to specific edges of the container using
dock north/south/east/west
.
class DockingExample { public static void main(String[] args) { JFrame frame = new JFrame("Docking Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // MigLayout with no column or row constraints (handled by dock) JPanel panel = new JPanel(new MigLayout("fill")); // "fill" ensures the container uses all space // Dock components to the edges panel.add(new JLabel("North (Top)"), "dock north"); panel.add(new JLabel("South (Bottom)"), "dock south"); panel.add(new JLabel("West (Left)"), "dock west"); panel.add(new JLabel("East (Right)"), "dock east"); // Add a central component panel.add(new JTextArea("Center (Remaining Space)"), "dock center"); frame.add(panel); frame.setSize(400, 300); // Set a size to observe docking frame.setVisible(true); } }
I build softwares that solve problems. I also love writing/documenting things I learn/want to learn.