How do I get a LinearLayout where the components are stacked on top of eachother in Swing?
I'm trying to create a custom JDialog
. I would like to have the components stacked on top of eachother with their preferred height, but the width should fill the container. S开发者_开发问答imilar to LinearLayout
in Android. I want that the components keeps their preferred height when the window is resized.
From Using Layout Managers:
Scenario: You need to display a few components in a compact row at their natural size.
Consider using a JPanel to group the components and using either the JPanel's default FlowLayout manager or the BoxLayout manager. SpringLayout is also good for this.
E.g. I would like to have a JTextField
above a JTabbedPane
. I have tried with all the suggested layout managers FlowLayout, BoxLayout, SpringLayout but they don't preserve the natural size of my components when the JDialog
window get increased height.
Is there any Layout Manager in Java Swing that I can use for my situation?
Here is a small example that shows my problem with the Swing layouts:
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
public class TestDialog extends JDialog {
public TestDialog() {
setLayout(new BoxLayout(this.getContentPane(), BoxLayout.PAGE_AXIS));
//setLayout(new SpringLayout());
JTextField field1 = new JTextField();
JTextField field2 = new JTextField();
JTextField field3 = new JTextField();
JTextField field4 = new JTextField();
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.PAGE_AXIS));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.PAGE_AXIS));
panel1.add(field2);
panel2.add(field3);
panel2.add(field4);
JTabbedPane tabs = new JTabbedPane();
tabs.addTab("Tab 1", panel1);
tabs.addTab("Tab 2", panel2);
add(field1);
add(tabs);
//field1.setMaximumSize(field1.getPreferredSize());
//SpringUtilities.makeCompactGrid(this.getContentPane(), 2, 1, 2, 2, 2, 2);
this.pack();
this.setVisible(true);
}
public static void main(String[] args) {
new TestDialog();
}
}
I would like to have a JTextField above a JTabbedPane. I have tried with all the suggested layout managers
A vertical BoxLayout should work fine. If the components grow when you increase the frame size then you may need to add:
textField.setMaximumSize( textField.getPreferredSize() );
tabbedPane.setMaximumSize( tabbedPane.getPreferredSize() );
If you need more help then post the SSCCE that demonstrates the problem.
Edit:
You need to specify your preferred size for text fields. This is done by using:
JTextField textField = new JTextField(10);
The null layout (basically x/y) might be what you are looking for, or perhaps Group Layout.
MigLayout also does what you probably want out of the box (you have to give it a specific directive to grow with the window, otherwise it doesn't).
Conceptually I think you are confused by the fact that the layout ultimately decides the size of components, so the "natural" size is a bit misleading. I guess what you are after is the size as set on the component? Or perhaps you mean the default when none of the setSize methods have been called on the component?
Either way, with Swing you have to be more explicit in your sizing expectations to get good results.
I quite didn't get what you meant by natural size of a component. But if you don't want the Layout manager messing up with the size of the components, i would suggest you use either the setMaximumSize(int width,int height)
or set the layout to null and use setBounds(int x,int y,int width,int height)
method to size your component.
If you are looking to tweak how the component's sizes change relative to each other, then i would suggest looking at GridBagLayout and using weightx and weighty properties.
I ended up with implementing my own StackLayout, the code is below. This is how the same application in my question look like. The components are stacked from top to bottom, and takes up the full width, similar to LinearLayout
for Android.
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
public class StackLayout implements LayoutManager {
@Override
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int maxWidth = parent.getWidth() - (insets.left + insets.right);
int y = insets.top;
for(int n = 0; n < parent.getComponentCount(); n++) {
Component c = parent.getComponent(n);
int height = c.getPreferredSize().height;
c.setBounds(0, y, maxWidth, height);
y += height;
}
}
@Override
public Dimension minimumLayoutSize(Container c) {
int sumHeight = 0;
int maxWidth = 0;
for(int n = 0; n < c.getComponentCount(); n++) {
Dimension preferredSize = c.getComponent(n).getPreferredSize();
if(n == 0) {
maxWidth = preferredSize.width;
} else {
maxWidth += preferredSize.width;
}
sumHeight += preferredSize.height;
}
// add the containers insets
Insets insets = c.getInsets();
sumHeight += insets.top + insets.bottom;
maxWidth += insets.left + insets.right;
return new Dimension(maxWidth, sumHeight);
}
@Override
public Dimension preferredLayoutSize(Container c) {
return minimumLayoutSize(c);
}
@Override
public void addLayoutComponent(String arg0, Component c) {}
@Override
public void removeLayoutComponent(Component c) {}
}
If you use GridBagLayout
and don't specify a fill or weight you should get what you want. Essentially you will have a 1 column 2 row grid bag layout. Just create your GridBagConstraints
and set only the x and y options when adding the components - do not set any other options.
I would suggest a much simpler layout manager - BorderLayout() - from what you are describing. Code follows: you need to specify width of at least 1 JTextField to set up the width of the JDialog. You can use EmptyBorder if you want some spacings. Hope this helps, - M.S.
import java.awt.*;
import javax.swing.*;
public class TestDialog extends JDialog {
private JTextField field1 = new JTextField(20),
field2 = new JTextField(),
field3 = new JTextField(),
field4 = new JTextField();
public TestDialog(Frame f) {
super (f, "Test Dialog");
Container cp = getContentPane();
cp.setLayout (new BorderLayout());
cp.add (northPanel(), "North");
cp.add (tabbedPane(), "Center");
pack();
}
private JPanel northPanel () {
JPanel nPanel = new JPanel(new BorderLayout());
nPanel.add (field1, "Center");
// nPanel.setBorder (...);
return nPanel;
}
private JTabbedPane tabbedPane () {
JTabbedPane tp = new JTabbedPane();
tp.add ("Tab 1", panel1());
tp.add ("Tab 2", panel2());
return tp;
}
private JPanel panel1 () {
JPanel tfPanel = new JPanel(new BorderLayout());
tfPanel.add (field2, "North");
return tfPanel;
}
private JPanel panel2 () {
JPanel tfPanel = new JPanel(new BorderLayout()),
t2Panel = new JPanel(new BorderLayout());
t2Panel.add (field3, "North");
t2Panel.add (field4, "Center");
tfPanel.add (t2Panel, "North");
return tfPanel;
}
public static void main (String[] args) {
new TestDialog (null).setVisible (true);
}}
精彩评论