admin管理员组文章数量:1279237
I need two horizontally positioned components in a container, both of them should fill all of their container's vertical space.
Do I now have to use the heavy-weight GridBagLayout
, because of the fill requirement? (and if I want it to flow to boot, bad luck, I'm out of options)
Java 8, Swing.
I need two horizontally positioned components in a container, both of them should fill all of their container's vertical space.
Do I now have to use the heavy-weight GridBagLayout
, because of the fill requirement? (and if I want it to flow to boot, bad luck, I'm out of options)
Java 8, Swing.
Share Improve this question asked Feb 24 at 6:36 CagepiCagepi 3091 silver badge7 bronze badges 12 | Show 7 more comments1 Answer
Reset to default 1As an alternative to GridBagLayout
for this scenario, you can use a BoxLayout
like so:
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BoxLayoutMain {
/**
* Specifies minimum and maximum sizes for each child {@code Component} of the
* {@linkplain BoxLayout#getTarget() target} of the given {@code BoxLayout}, such that aspect
* ratios of their preferred size are maintained throughout parent resizing. Assumes all
* children of the target are already added to it. Assumes the layout is horizontal.
* @param boxLayout
*/
private static void assignHorizontalBoxLayoutChildWeights(final BoxLayout boxLayout) {
final int maxValue = Short.MAX_VALUE;
final Container parent = boxLayout.getTarget();
final int totalWidth = parent.getPreferredSize().width;
final Dimension commonMinimumSize = new Dimension();
for (final Component child: parent.getComponents()) {
child.setMinimumSize(commonMinimumSize);
final Dimension prefSize = child.getPreferredSize();
child.setMaximumSize(new Dimension((int) Math.round(maxValue * (prefSize.width / (double) totalWidth)), maxValue));
}
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final JLabel component1 = new JLabel("Component 1", JLabel.CENTER);
component1.setBorder(BorderFactory.createLineBorder(Color.RED, 5));
final JLabel component2 = new JLabel("Component 2 (which is a little longer)", JLabel.CENTER);
component2.setBorder(BorderFactory.createLineBorder(Color.GREEN, 5));
final JPanel parent = new JPanel();
parent.setBorder(BorderFactory.createLineBorder(Color.BLUE, 5));
final BoxLayout layout = new BoxLayout(parent, BoxLayout.X_AXIS);
parent.setLayout(layout);
parent.add(component1);
parent.add(component2);
assignHorizontalBoxLayoutChildWeights(layout);
final JFrame frame = new JFrame("Box for no gridbag");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(parent);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
This produces the following result:
When the parent Container
is resized the children maintain their width aspect ratios, while always filling their whole height.
Nevertheless, sadly, a minor gap can be observed between green and blue borders on the right side of the parent when it is resized. This is shown in the brown circle in the following image:
This may not be a problem though depending on the situation (eg in case you are not using any borders for the children in the above code).
Update:
SpringLayout
also comes to mind for this scenario:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Spring;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;
public class SpringLayoutMainWithoutFixedSizes {
private static Component createComponent(final String label,
final Color borderColor) {
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(borderColor, 5));
if (label != null) {
final JLabel c = new JLabel(label, JLabel.CENTER);
panel.add(c, BorderLayout.CENTER);
}
return panel;
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final Component component1 = createComponent("Component 1", Color.RED),
component2 = createComponent("Component 2 (which is a little longer)", Color.GREEN);
final SpringLayout layout = new SpringLayout();
final JPanel parent = new JPanel(layout);
parent.setBorder(BorderFactory.createLineBorder(Color.BLUE, 5));
parent.add(component1);
parent.add(component2);
final SpringLayout.Constraints constraints1 = layout.getConstraints(component1),
constraints2 = layout.getConstraints(component2),
constraintsParent = layout.getConstraints(parent);
//Component 2 x will be equal to component 1 width:
constraints2.setX(constraints1.getWidth());
//The width of the container will be equal to the summary of the width of the two children:
constraintsParent.setWidth(Spring.sum(constraints1.getWidth(), constraints2.getWidth()));
//The height of the container will be equal to the maximum height between the two children:
constraintsParent.setHeight(Spring.max(constraints1.getHeight(), constraints2.getHeight()));
final JFrame frame = new JFrame("Spring for no gridbag");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(parent);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Which is not explicitly setting minimum/maximum/preferred sizes per child.
Notice however here that the width ratio of the preferred sizes of the children is not preserved intact as we resize the window. This is because of the values of minimum and maximum sizes per child, which are also taken into account. This is true for both SpringLayout
and BoxLayout
. For example, because the children have equal maximum sizes, their width ratio tends to 1 as we enlarge the window. In other words they tend to occupy equal space horizontally for sizes greater than the preferred ones.
I also wrap the JLabel
children into a JPanel
each, because JLabel
s by default have minimum and maximum sizes equal to their preferred size, thus the width ratio change could not be observed by JLabel
s without manually setting their minimum and maximum sizes.
Follows a BoxLayout
approach equivalent to the posted SpringLayout
one:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BoxLayoutMainWithoutFixedSizes {
private static Component createComponent(final String label,
final Color borderColor) {
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(borderColor, 5));
if (label != null) {
final JLabel c = new JLabel(label, JLabel.CENTER);
panel.add(c, BorderLayout.CENTER);
}
return panel;
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final Component component1 = createComponent("Component 1", Color.RED),
component2 = createComponent("Component 2 (which is a little longer)", Color.GREEN);
final JPanel parent = new JPanel();
parent.setBorder(BorderFactory.createLineBorder(Color.BLUE, 5));
final BoxLayout layout = new BoxLayout(parent, BoxLayout.X_AXIS);
parent.setLayout(layout);
parent.add(component1);
parent.add(component2);
final JFrame frame = new JFrame("Box for no gridbag");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(parent);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
The above (last) code does not explicitly set minimum nor maximum sizes per child, but on the other hand the width ratio is not preserved for the same reason as for the SpringLayout
code (ie exactly because we are not settings sizes, which are taken into account by these two LayoutManager
s).
Note, I now understand that you want an equivalent solution to GridBagLayout
without explicitly setting minimum/maximum/preferred sizes, but I leave the above ideas as close alternatives.
In case there is a need for the user to be able to determine manually the width of each Component
then you could use a JSplitPane
instead.
本文标签: javaAvoiding GridBagLayoutstill ensuring vertical fillStack Overflow
版权声明:本文标题:java - Avoiding GridBagLayout, still ensuring vertical fill - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741289910a2370488.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
GridBagLayout
really a bottleneck? Memory, speed, or what? – user85421 Commented Feb 24 at 7:51BorderLayout.LINE_START
? Doesn't aBorderLayout
-managed container have only four areas? – Cagepi Commented Feb 24 at 8:06