Swing BoxLayout problem - Can't make the Fillers do their job
Asked Answered
T

3

7

What i'm trying to do

In Swing, I'm trying to use a BoxLayout or equivalent linear container, but the items in the container are stretching vertically. Inside my application, I don't want them to stretch vertically.

I know i could set a preferredSize or maximumSize on components, but the following code is just a reproducer, and I can't hard-code or maximize the size of the components, which are in reallity more complex and dynamic. And I just can't use a BorderLayout with the BorderLayout.TOP position, because no scroll bars will ever show if I do that. And I might need scroll panes.


What I have tried

So I tried to use the fillers in a BoxLayout as explained in Using Invisible Components as Filler , but it just doesn't work. Although in the Oracle documentation, it seemed to be exactly what I needed. Here are my attempts:

    import javax.swing.Box;
    import javax.swing.BoxLayout;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;


    public class TestBoxLayout implements Runnable {

        public static void main(String[] args) {
            SwingUtilities.invokeLater(new TestBoxLayout());
        }

        @Override
        public void run() {
            JFrame f = new JFrame("test box layout");

            JPanel b = new JPanel();
            b.setLayout(new BoxLayout(b, BoxLayout.PAGE_AXIS));

            b.add(new JTextField("field 1"));
            b.add(new JTextField("field 2"));
            b.add(new JTextField("field 3"));
            b.add(Box.createVerticalGlue());

            f.setContentPane(b);
            f.setSize(500, 200);
            f.setVisible(true);
        }

    }

This is the result I get:

Fillers are not working


Second try

I tried to use the Box class instead of JPanel with BoxLayout, but the visual result is exactly the same. Here is my second try:

    import javax.swing.Box;
    import javax.swing.JFrame;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;


    public class TestBox implements Runnable {

        public static void main(String[] args) {
            SwingUtilities.invokeLater(new TestBox());
        }

        @Override
        public void run() {
            JFrame f = new JFrame("test box");

            Box b = Box.createVerticalBox();

            b.add(new JTextField("field 1"));
            b.add(new JTextField("field 2"));
            b.add(new JTextField("field 3"));
            b.add(Box.createVerticalGlue());

            f.setContentPane(b);
            f.setSize(500, 200);
            f.setVisible(true);
        }

    }

What I would like to do

Does anyone know how I can fix those fillers and make them work ? A fix on the given code would be fantastic.

This is a drawing I made using paint, which shows what I'd like to have as a result: Expected result

Thundery answered 29/6, 2011 at 13:6 Comment(1)
BoxLayout is fine for what you are trying to do. The glue insert as last component is fine. Why aren't simply using setMaximum/Preferred/Size methods to limit the dimension of your TextFields?Arnettaarnette
A
2

BoxLayout is fine for what you are trying to do. The glue insert as last component is fine. Why aren't simply using setMaximumSize methods on your JTextFields? I'm not sure JTextFields alone can satisfy your needs. If using setMaximumSize don't work put each JTextField Inside a JPanel and then use setMaximumSize on each JPanel.

Arnettaarnette answered 29/6, 2011 at 13:15 Comment(5)
As I explained, the components inside the BoxLayout are dynamic -as in produced by a framework- and this is only a reproducer. I just cannot compute that size.Thundery
ok..the number of components is dynamic but the maximum size, as showed by your images, is fixed. Shouldn't they be always the same size despite of the number of it?Arnettaarnette
I just cannot compute that size. It's only a reproducer.Thundery
whad do you mean exactly with "I just cannot compute that size"?Arnettaarnette
I don't know the size of a component. I know there is a way to have a correct default size because a borderlayout would compute it automatically. But I can't use a borderlayout because it disables scroll bars.Thundery
A
1

OP asked how he can make BoxLayout respect vertical glue with JTextFields only. The text field maximum height can be set from getPreferredSize().

However, in my case I also need JTextArea, and the situation gets more weird: JTextArea and vertical glue seem to share the remaining height together, although I have limited the maximum height of the JTextArea.

The code below fixes the OP problem with JTextFields, but the problem with JTextArea remains (when you uncomment the commented part you will see some "funny" behavior).

import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class TestBox implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TestBox());
    }

    @Override
    public void run() {
        JFrame f = new JFrame("test box");

        Box b = Box.createVerticalBox();

        JTextField field1 = new JTextField();
        JTextField field2 = new JTextField();
        field1.setMaximumSize(new Dimension(Integer.MAX_VALUE, field1.getPreferredSize().height));
        field2.setMaximumSize(new Dimension(Integer.MAX_VALUE, field2.getPreferredSize().height));
        b.add(field1);
        b.add(field2);

//        JTextArea area = new JTextArea();
//        area.setRows(4);
//        area.setMaximumSize(new Dimension(Integer.MAX_VALUE, area.getPreferredSize().height));
//        b.add(new JScrollPane(area));

        b.add(Box.createVerticalGlue());

        f.setContentPane(b);
        f.setSize(500, 200);
        f.setVisible(true);
    }
}
Acetamide answered 6/8, 2012 at 14:40 Comment(0)
Y
0

Many posts decry Box's shortcomings with glue size and content alignment. These problems arise from BoxLayout's use of SizeRequirements methods calculateTiledPositions and calculateAlignedPositions. These methods are elegantly brief but so simplistic that the results often fail to match expected behavior.

A workaround for the original question is to set a large value for the glue's preferred size:

    Box.Filler glue = (Box.Filler) Box.createVerticalGlue();
    glue.changeShape(glue.getMinimumSize(), 
           new Dimension(0, Short.MAX_VALUE),   // prefer it big
           glue.getMaximumSize());
    b.add(glue);

This works for three JTextFields, but not when a scrolled JTextArea is added. The more general solution is to set the Box's LayoutManager to a BoxLayout subclass that rewrites layoutContainer(). Replace the calls to the above methods with code that better suits your needs.

Yacano answered 4/9, 2014 at 1:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.