Reputation: 733
I have a panel that consists of a button (X), a label (Y), and a progress bar (Z). Ideally I would like to lay them out like so:
| X-X Y---------------Y Z---Z ============= | <-- expanded-size panel
^ extra space
| X-X Y------Y Z---Z | <-- reduced-size panel
The diagram above shows:
However, when I try using GroupLayout, this is what happens when the panel is expanded:
| X-X Y---------------Y ============= Z---Z | <-- expanded-size panel (bad)
The problem is that when the panel has extra space, the label (Y) gets expanded beyond what it needs, which pushes the progress bar (Z) to the right. I would prefer that the progress bar's (Z) position is next to the label (Y).
How can I accomplish this layout?
Example code ("Blah.java"):
import java.awt.*;
import javax.swing.*;
public class Blah extends JPanel {
public Blah() {
final JButton X = new JButton("X");
final JLabel Y = new JLabel("yyyyyyyyyyy");
Y.setOpaque(true);
Y.setBackground(Color.YELLOW);
final JProgressBar Z = new JProgressBar();
Z.setIndeterminate(true);
final GroupLayout l = new GroupLayout(this);
super.setLayout(l);
l.setHorizontalGroup(
l.createSequentialGroup()
.addComponent(X, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(Y, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(Z, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
l.setVerticalGroup(
l.createParallelGroup()
.addComponent(X)
.addComponent(Y)
.addComponent(Z));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame frame = new JFrame("Blah");
frame.add(new Blah());
frame.pack();
frame.setVisible(true);
}
});
}
}
Upvotes: 4
Views: 326
Reputation: 733
After banging my head against the wall for far too long, I discovered this little gem of documentation in SpringLayout
's tutorial (http://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html):
When a component's
getMaximumSize
andgetPreferredSize
methods return the same value,SpringLayout
interprets this as meaning that the component should not be stretched.
Thus with SpringLayout
and manually setting Y
's and Z
's maximum size, the ideal layout outlined above can be achieved. Here's the code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Blah extends JPanel {
public Blah() {
final JButton X = new JButton("X");
final JLabel Y = new JLabel("yyyyyyyyyyy");
Y.setOpaque(true);
Y.setBackground(Color.YELLOW);
final JProgressBar Z = new JProgressBar();
Z.setIndeterminate(true);
final SpringLayout l = new SpringLayout();
super.setLayout(l);
super.add(X);
super.add(Y);
super.add(Z);
Z.setMaximumSize(Z.getPreferredSize());
l.putConstraint(SpringLayout.WEST, X, 10, SpringLayout.WEST, this);
l.putConstraint(SpringLayout.WEST, Y, 10, SpringLayout.EAST, X);
l.putConstraint(SpringLayout.WEST, Z, 10, SpringLayout.EAST, Y);
l.putConstraint(SpringLayout.EAST, this, 10, SpringLayout.EAST, Z);
l.putConstraint(SpringLayout.NORTH, X, 10, SpringLayout.NORTH, this);
l.putConstraint(SpringLayout.NORTH, Y, 10, SpringLayout.NORTH, this);
l.putConstraint(SpringLayout.NORTH, Z, 10, SpringLayout.NORTH, this);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame frame = new JFrame("Blah");
frame.add(new Blah());
frame.pack();
frame.setVisible(true);
}
});
}
}
Upvotes: 0
Reputation: 347184
It is very rare that one individual layout manager will meet all your needs. Instead you could use a compound layout approach.
That is, separate each individual layout requirement into a separate component, with it's own layout manager. Then added all these to your master component, managing the overall requirements.
As an example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class SimpleGridBagLayout {
public static void main(String[] args) {
new SimpleGridBagLayout();
}
public SimpleGridBagLayout() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
add(createLabel("XXX-XXX", Color.BLUE), gbc);
JPanel panel = new JPanel();
panel.add(createLabel("Y-Y", Color.RED));
panel.add(createLabel("ZZZZZ---ZZZZZ", Color.GREEN), gbc);
gbc.gridx++;
gbc.weightx = 1;
add(panel, gbc);
}
protected JLabel createLabel(String text, Color border) {
JLabel label = new JLabel(text);
label.setBorder(new LineBorder(border));
return label;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
}
}
There are a number of factors at play here. The preferred and minimum sizes of the child components will make a significant difference to how some layout managers layout there components when the available size is to small.
Updated
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
add(createLabel("XXX-XXX", Color.BLUE), gbc);
JPanel panel = new JPanel(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
panel.add(createLabel("Y-Y", Color.RED), gbc);
gbc.gridx = 1;
panel.add(createLabel("ZZZZZ---ZZZZZ", Color.GREEN), gbc);
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.weightx = 1;
add(panel, gbc);
}
Updated
Now with "non-shrinking" progress bar
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
add(createLabel("XXX-XXX", Color.BLUE), gbc);
JPanel panel = new JPanel(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
panel.add(createLabel("Y-Y", Color.RED), gbc);
gbc.gridx = 1;
MyProgressBar pb = new MyProgressBar();
panel.add(pb, gbc);
gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.weightx = 1;
add(panel, gbc);
}
protected JLabel createLabel(String text, Color border) {
JLabel label = new JLabel(text);
label.setBorder(new LineBorder(border));
return label;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
}
public class MyProgressBar extends JProgressBar {
@Override
public Dimension getPreferredSize() {
Dimension ps = super.getPreferredSize();
ps.width = 75;
return ps;
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
}
Upvotes: 4