MigLayout: How to *vertically* align multiple components inside a dock? - java

MigLayout supports adding multiple components to a dock. I want to add multiple components to the west dock, from top to bottom. However, it seems as if MigLayout can only manage a horizontal layout inside a dock. I tried many parameters (e.g., wrap, growy, flowy) without success.
So, is there any possibility to wrap or set a vertical flow inside a dock? Or is this not possible with MigLayout itself, but only by using an extra sidepanel-component?
Here an example of the unwanted horizontal layout inside the west dock:
How to get the red, green, blue components below each other? Here is the code:
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
public class MigTest extends JFrame {
MigTest() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(800, 600);
setLayout(new MigLayout("fill"));
JTextField dockW1 = new JTextField("West 1"); dockW1.setBackground(Color.red);
JTextField dockW2 = new JTextField("West 2"); dockW2.setBackground(Color.green);
JTextField dockW3 = new JTextField("West 3"); dockW3.setBackground(Color.blue);
JTextField center = new JTextField("Center"); center.setBackground(Color.lightGray);
add(center, "grow");
// HOW TO LAYOUT THESE COMPONENTS VERTICALLY INSIDE WEST DOCK ?
add(dockW1, "dock west, wrap, growy, flowy");
add(dockW2, "dock west, wrap, growy, flowy");
add(dockW3, "dock west, wrap, growy, flowy");
setVisible(true);
}
public static void main(String[] args) {
new MigTest();
}
}
[edit]: Note that I do not want to put dockW1, dockW2,dockW3, and center into a single grid, since I plan to apply a complex layout in the center area, independently of the side-area, which is the reason why the docking feature was invented :)

My first suggestion is to change the constructor of the MigLayout to
new MigLayout("fill","[][grow]","[][][]")
Then change your add statement to :
add(center, "cell 1 0 1 3, grow");
add(dockW1, "cell 0 0");
add(dockW2, "cell 0 1");
add(dockW3, "cell 0 2");
Edit
After you edited the question, I would suggest you to create a new JPanel object say dockWest and add the components dockW1, dockW2 and dockW3 to dockWest and finally dock the dockWest to the west of the current JFrame like:
JPanel dockWest = new JPanel();
dockWest.setLayout(new MigLayout("fill", "[]", "[grow][grow][grow]");
dockWest.add(dockW1, "cell 0 0");
dockWest.add(dockW2, "cell 0 1");
dockWest.add(dockW3, "cell 0 2");
add(dockWest, "dock west, growy");

IMHO the side-panel is easier option with the same result.
You can also try using cell coordinates as written on page 2 in Quick guide.

Related

How to create a fluid 2-column GridLayout within a ScrollPane?

I have done tons of searching over the past two hours, and I've given up. The image below shows what I am trying to achieve (don't judge my drawing it's late and I made it in paint quickly):
Basically, I want a JScrollPane to have a JPanel with a 2-column GridLayout, and as I add elements I want the GridLayout to expand downward. I want the elements to use their Preferred Size and to NOT expand within the GridLayout.
Currently I have a JScrollPane and a JPanel with a GridLayout, and a JPanel containing the grid with a FlowLayout. As a test, I add 10 buttons to the grid. Here's my current code:
// Setup main panel
JPanel pnlUsers = new JPanel(new GridLayout(0, 2));
pnlUsers.setOpaque(true);
pnlUsers.setBackground(Color.GREEN);
// Setup GridLayout Container
JPanel pnl2 = new JPanel();
pnl2.setOpaque(false);
pnl2.add(pnlusers);
// Setup scrollpane
JScrollPane scrUsers = new JScrollPane(pnl2);
scrUsers.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrUsers.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrUsers.setOpaque(false);
scrUsers.getViewport().setOpaque(false);
scrUsers.setBorder(null);
// Add users
for (int i = 0; i < 10; i++) {
pnlUsers.add(new JButton("Button " + (i + 1));
}
This gives a very good result, with the buttons using their preferred size as seen in the image below:
Unfortunately, the buttons are still not filling the horizontal space. So, I attempted to make pnl2 a BoxLayout instead and add some vertical glue...
// Setup GridLayout Container
JPanel pnl2 = new JPanel();
pnl2.setLayout(new BoxLayout(pnl2, BoxLayout.Y_AXIS));
pnl2.setOpaque(false);
pnl2.add(pnlusers);
pnl2.add(Box.createVerticalGlue());
I also created my own temporary button class that sets the preferred size to use the minimum size:
public class TempButton extends JButton {
public PLTempButton(String msg) {
super(msg);
this.setPreferredSize(this.getMinimumSize());
}
}
Which resulted in the following:
This is much better, but there's still a problem. If there are not enough buttons to cause the JScrollPane to scroll, the buttons height are not consistent and will resize as you resize the window vertically. Why?
Obviously when I add 100 buttons, they use their preferred size:
Maybe I'm just not understanding the differences between minimum, preferred and maximum size? But I want the buttons to use the height they're set even if there aren't enough to cause the scroll-pane to, well, scroll. What can I do to fix this?
1) How do I even get a GridLayout within a ScrollPane?
Create a JPanel
Apply a GridLayout to the JPanel
Wrap the JPanel in a JScrollPane
For example
JPanel panel = new JPanel(new GridLayout(0, 2));
JScrollPane scrollPane = new JScrollPane(panel);
// Add the scroll pane to what ever parent container you're using
2) How do I get said GridLayout to expand horizontally, including the added components?
That doesn't make sense with regards to all previous part of the question, you said "and have it slowly expand downward the more things I add"
Having said that, the "basic" answer is, you configure the GridLayout and let it do it's job. The above example is configured for 2 columns and n number of roes
3) How would I add a "margin" to the components?
That's a broad answer, you could:
Make use of the horizontal and vertical gap properties of the GridLayout
Use a compound layout and adjust the insets of the an appropriate layout manager (like GridBagLayout)
Recommendations
I would recommend reading through Laying Out Components Within a Container to get a better understanding of the layout managers.
Remember, you not stuck to using one.
I would also recommend reading through How to Use Scroll Panes as you're asking basic questions about the API which are better covered through the tutorials
The following mre demonstrates creating a JPanel with GridLayout warped by JScrollPane and setting its horizontal and vertival gaps.
The Jpanel is added using a BorderLayout (the default layout manager of JFrame content pane) which allows it to expand:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class SwingMain {
private String text ="Growing ";
private JPanel grid;
private JFrame f;
SwingMain() {
creategui();
}
void creategui(){
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
JButton addComponentBtn = new JButton("Add Component");
addComponentBtn.addActionListener(e-> addComponent());
f.add(addComponentBtn, BorderLayout.PAGE_START);
grid = new JPanel(new GridLayout(0, 2, 10, 10)); //any number of rows, 2 columns, H and V gap
f.add(new JScrollPane(grid), BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
void addComponent() {
grid.add(new JLabel(text) );
text +="."; //make text longer so JLable grows
f.pack();
}
public static void main(String[] args) {
new SwingMain();
}
}

Miglayout or an alternative layout manager

i'm currently learning Java Swing and came across what I think is an interesting topic that I couldn't find an answer to online. So my question is i've got a JFrame using Miglayout but it's not working the way I would like it to. I'll post a picture of what it's currently looking like and what I want it to look like and i'll also post my code. Also, i've tried to put a JPanel on a JPanel and then move them around using Miglayout but that didn't work. Will Miglayout work with this or would another layout manager be better?
EDIT
What I want it to look like is have a JTextArea and right next to it have 3 JRadioButtons grouped together but the radio button at the bottom of the stack reformats itself so it ends up at the bottom of the JTextArea
public SecondFrame() {
formPanel.setLayout(new net.miginfocom.swing.MigLayout());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(500, 525);
f.setVisible(true);
f.setLocationRelativeTo(null);
//by adding the buttons to a group it will only allow you to select 1 button at a time
buttonGroupLocation.add(sydney);
buttonGroupLocation.add(melbourne);
buttonGroupLocation.add(brisbane);
buttonGroupSeverityLevels.add(lowSeverityBtn);
buttonGroupSeverityLevels.add(mediumSeverityBtn);
buttonGroupSeverityLevels.add(highSeverityBtn);
buttonGroupSeverityLevels.add(criticalSeverityBtn);
formPanel.add(sydney, "cell 0 0 1 1");
formPanel.add(melbourne, "cell 0 1 1 1, wrap");
formPanel.add(brisbane, "cell 0 2 1 1, wrap");
formPanel.add(issue, "cell 1 0 1 1, wrap");
formPanel.add(issueArea, "span ");
formPanel.add(solution, "cell 0 8 1 1, wrap");
formPanel.add(solutionArea, "cell 0 15 8 1");
formPanel.add(severity, "cell 0 4 1 1, wrap");
formPanel.add(lowSeverityBtn, "cell 0 5 1 1");
formPanel.add(mediumSeverityBtn, "cell 1 5 1 1");
formPanel.add(highSeverityBtn, "cell 2 5 1 1");
formPanel.add(criticalSeverityBtn, "cell 3 5 1 1");
formPanel.add(submit, "cell 0 16 1 1");
formPanel.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
f.add(formPanel);
formPanel.add(submit, "cell 0 16 1 1");
If MigLayout cannot do it, other layout managers will hardly do it.
For MigLayout, this is a piece of cake. There are several ways how
to accomplish your task. I have done it by placing the three radio
buttons into one cell. This can be done by splitting the cell into three
subcells.
package com.zetcode;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
public class MigLayoutAirportEx extends JFrame {
public MigLayoutAirportEx() {
initUI();
}
private void initUI() {
setLayout(new MigLayout());
ButtonGroup bg = new ButtonGroup();
JRadioButton sydn = new JRadioButton("Sydney");
JRadioButton melb = new JRadioButton("Melbourne");
JRadioButton bris = new JRadioButton("Brisbane");
bg.add(sydn);
bg.add(melb);
bg.add(bris);
JLabel issue = new JLabel("Issue");
JTextArea area = new JTextArea(15, 20);
area.setBorder(BorderFactory.createEtchedBorder());
add(sydn, "split 3, flowy, aligny top");
add(melb);
add(bris);
add(issue, "split 2, flowy");
add(area, "push, grow, wrap");
pack();
setTitle("ARE - Airport Retail Enteprises");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MigLayoutAirportEx ex = new MigLayoutAirportEx();
ex.setVisible(true);
});
}
}
The example creates the upper part of your UI where you have your issue.
Also, i've tried to put a JPanel on a JPanel and then move them around
using Miglayout but that didn't work.
These are inherited bad habits from poor layout managers. With MigLayout, you do not need any additional panels with other layout managers. Powerful layout managers do not need this.
And here is the screenshot:

Use BorderLayout to create two even columns

I'm trying to create a program using BorderLayout() that I want to look like this (but with even left right height and such)
although I am having trouble resizing the two JPanels (two boxes within the large box). At the moment my GUI looks like this,
I believe it is due to the CENTER still being there, I looked up on how to remove it but could not get it to work,
Question
Can can I edit this so that it will look like the top image.
package fuelstation;
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class Fuelstation extends JFrame {
JButton btn1 = new JButton("Random Button");
public Fuelstation() {
JFrame frame = new JFrame("Fuel Station");
frame.setLayout(new BorderLayout());
frame.setResizable(false);
frame.setPreferredSize(new Dimension(500,350));
frame.setMaximumSize(new Dimension(500,350));
// Left Hand Side
JPanel lhs = new JPanel();
JTextArea tf_list = new JTextArea();
tf_list.setEditable(false);
tf_list.setWrapStyleWord(true);
tf_list.setText("This is a list of items");
lhs.add(tf_list);
tf_list.setSize(245, 325);
lhs.setBorder(BorderFactory.createTitledBorder("Left"));
// Left Hand Side End
// Right Hand Side
JPanel rhs = new JPanel();
rhs.setAlignmentX(Component.CENTER_ALIGNMENT);
rhs.setBorder(BorderFactory.createTitledBorder("Right"));
rhs.add(btn1);
tf_list.setSize(245, 325);
JPanel center = new JPanel();
center.setSize(0, 0);
// Right Hand Side End
frame.add(lhs, BorderLayout.WEST);
frame.add(center, BorderLayout.CENTER);
frame.add(rhs, BorderLayout.EAST);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
Fuelstation gui = new Fuelstation();
}
}
You need to drop the requirement to use a BorderLayout. The resizing policy for components when using a BorderLayout is stated in the class javadoc
The components are laid out according to their preferred sizes and the constraints of the container's size. The NORTH and SOUTH components may be stretched horizontally; the EAST and WEST components may be stretched vertically; the CENTER component may stretch both horizontally and vertically to fill any space left over.
By forcing your JFrame to a certain size
frame.setResizable(false);
frame.setPreferredSize(new Dimension(500,350));
frame.setMaximumSize(new Dimension(500,350));
your center component will take the extra width, as the EAST and WEST component will only stretch vertically.
So you need to use another LayoutManager. You can use the Visual guide to layout managers to get a grasp of the available LayoutManagers and their capabilities. That document states that a GridLayout would be a good candidate:
GridLayout simply makes a bunch of components equal in size and displays them in the requested number of rows and columns

"Inline" list of checkboxes - auto line break

I have a JPanel (extended by my GeneralOptions class) implemented as:
public GeneralOptions() {
setLayout(new MigLayout("", "[grow]", "[][][][]"));
JLabel lblWyzywienie = new JLabel("Food");
add(lblWyzywienie, "cell 0 0");
JCheckBox chckbxHb = new JCheckBox("HB");
add(chckbxHb, "cell 0 1");
JCheckBox chckbxBb = new JCheckBox("BB");
add(chckbxBb, "cell 0 1,alignx trailing");
JCheckBox chckbxAll = new JCheckBox("All Inclusive");
add(chckbxAll, "cell 0 1,alignx trailing");
}
As you can see, there is a list of checkboxes in one cell of MigLayout. This JPanel in placed as left panel of SplitPanel component, so its width is resizable.
What I want to achieve is to force this list of checkboxes to act like "inline" html list of checkboxes. This means, that they should break line when width of panel is not enough to show them in single line.
Now I can't resize this panel below width of whole list and if init width is less than this list of checkboxes, some of them are just hidden.
Example html code
http://jsfiddle.net/
You can try to resize right panel to see what I'm talking about.
Take a look on the following discussion: http://migcalendar.com/forums/viewtopic.php?f=8&t=2393
Scroll down to see the code. He actually implemented his own layout manager that does exactly what you want.

Question about making a JAVA GUI of a certain format

I am trying to make a GUI that looks something like this:
I only know how to use the BorderLayout which has space for 5 buttons. North, West, Center, East, and South.
Since I need to have 6 components on the top line, this approach can't work. I'm not sure how to make it so that I can have more than 1 component on the top line. Are there other layouts that I can use or is there some way I can manipulate BorderLayout so that I can put 6 components on the top line?
What you need to do is nest components inside of other components. For example, the top (North) should be one JPanel. That JPanel will contain the 6 components on the top.
The code may look similar to the following:
JPanel northPane = new JPanel();
northPane.add(new JLabel("Principle: "));
northPane.add(principleTextBox);
... and so on
mainPanel.setLayout(new BorderLayout());
mainPanel.add(northPanel, BorderLayout.NORTH);
The Center component will probably be another JPanel containing the two center buttons. And the South component will be another JPanel containing the single JLabel or simply the JLabel.
If you don't have to use a BorderLayout for the main panel, it may be easier to use a BoxLayout.
Once again I turn to miglayout, the absolute best layout manager for Java. No nested JPanels, just a simple layout using string based constraints.
With debug mode on:
After resizing the window (note the ratio of the size of the textfields remains the same)
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
/**
*
* #author nicholasdunn
*/
public class InterestCalculator extends JPanel {
public InterestCalculator() {
super(new MigLayout("debug, fill", "align center"));
// Make 6 components cram into one cell
add(new JLabel("Principal:"), "split 6");
// This textfield grows at twice the normal rate
add(new JTextField(), "growx 200");
add(new JLabel("Interest rate (percentage):"));
// This one at a normal rate
add(new JTextField(), "growx 100");
add(new JLabel("Years:"));
// This one at half the normal rate
add(new JTextField(), "growx 50, wrap");
// The row with the two buttons
add(new JButton("Compute simple interest"), "split 2");
add(new JButton("Compute compound interest"), "wrap");
// The result label
add(new JLabel("The result with simple interest would be"));
}
public static void main(String[] args) {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new InterestCalculator();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
If I were recreating that UI, I would start with a JPanel using a GridLayout with 3 rows and 1 column. In each column I would add a child JPanel.
Then for each row I would use a GridBagLayout to position the components.
Here is a tutorial about layout managers.
Remember that you can always add several elements to a JPanel and apply a specific layout to that JPanel. Then you can nest panels(add panels inside other panels).

Categories

Resources