How to set component size inside container with BoxLayout

58.2k views Asked by At

I'm facing a problem with using BoxLayout.

In my example, I try to decrease the height of the text field and change the width of the buttons (as shown in green marker in the picture at the bottom). I know about the techniques setPreferredSize() and setMaximumSize(), but it did not work as it should. The line add(Box.createHorizontalGlue()) also did not help.

Thanks for any ideas.


public class Testy extends JPanel {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                constructGUI();
            }
        });
    }

    private static void constructGUI() {
        JFrame frame = new JFrame("Testy");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel centerPanel = new JPanel();
        centerPanel.setBackground(Color.DARK_GRAY);
        centerPanel.setPreferredSize(new Dimension(100, 400));
        frame.add(centerPanel, BorderLayout.CENTER);

        Testy eastPanel = new Testy();
        frame.add(eastPanel, BorderLayout.EAST);

        frame.pack();
        frame.setVisible(true);
    }

    public Testy() {
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

        JButton button = new JButton("Button ...... 1");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        add(button);

        button = new JButton("Button 2");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        add(button);

        button = new JButton("Button ........... 3");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        add(button);

        JLabel label = new JLabel("Label");
        //label.setPreferredSize(...);
        //label.setMaximumSize(...);
        add(label);

        JTextField textField = new JTextField();
        //textField.setPreferredSize(...);
        //textField.setMaximumSize(...);
        add(textField);

        button = new JButton("Button 4");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        add(button);

        //add(Box.createHorizontalGlue());
    }
}

picture

3

There are 3 answers

6
Boris Šuška On BEST ANSWER

First you have to realize that component position and size in Java Swing depends on Layout manager (if layout manager is set) not on the component itself. The component requests the manager for size.

For this case I would use different layout - combination of GridLayout and BorderLayout is enough and very simple and straightforward. But if want use BoxLayout, then...

  1. Documentation says:

    BoxLayout pays attention to a component's requested minimum, preferred, and maximum sizes. While you are fine-tuning the layout, you might need to adjust these sizes. ... For example, a button's maximum size is generally the same as its preferred size. If you want the button to be drawn wider when additional space is available, then you need to change its maximum size.

  2. Then set components maximum size: c.setMaximumSize(new Dimension(Integer.MAX_VALUE, c.getMinimumSize().height)); (c means button, label and textField in your example)

Edit 1:

Here is working source code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;

public class Testy extends JPanel {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                constructGUI();
            }
        });
    }

    private static void constructGUI() {
        JFrame frame = new JFrame("Testy");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel centerPanel = new JPanel();
        centerPanel.setBackground(Color.DARK_GRAY);
        centerPanel.setPreferredSize(new Dimension(100, 400));
        frame.add(centerPanel, BorderLayout.CENTER);

        Testy eastPanel = new Testy();
        frame.add(eastPanel, BorderLayout.EAST);

        frame.pack();
        frame.setVisible(true);
    }

    public Testy() {
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

        JButton button = new JButton("Button ...... 1");
        //button.setPreferredSize(...);
        button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
        add(button);

        button = new JButton("Button 2");
        //button.setPreferredSize(...);
        button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
        add(button);

        button = new JButton("Button ........... 3");
        //button.setPreferredSize(...);
        button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
        add(button);

        JLabel label = new JLabel("Label");
        //label.setPreferredSize(...);
        label.setMaximumSize(new Dimension(Integer.MAX_VALUE, label.getMinimumSize().height));
        add(label);

        JTextField textField = new JTextField();
        //textField.setPreferredSize(...);
        textField.setMaximumSize(new Dimension(Integer.MAX_VALUE, textField.getMinimumSize().height));
        add(textField);

        button = new JButton("Button 4");
        //button.setPreferredSize(...);
        button.setMaximumSize(new Dimension(Integer.MAX_VALUE, button.getMinimumSize().height));
        add(button);

        // add(Box.createVerticalGlue());
    }
}

Screenshot

Edit 2:

If you want laid out Button 4 at the bottom of right column add this line add(Box.createVerticalGlue()); between add(textField); and button = new JButton("Button 4");.

1
Fernando On

This should get close, based on your draw, just need to work on that component below the JLabel (using setPreferredSize()):

JPanel main = new JPanel(new GridLayout(1, 2));

JPanel left = new JPanel();
//left.setPreferredSize(some size);
JPanel right = new JPanel(new GridLayout(6, 1));
//right.setPreferredSize(some size);

right.add(new JButton("Button 1"));
//...
right.add(new JButton("Button 4"));

main.add(left);
main.add(right);
1
nIcE cOw On

As a quick remedy, you can use nested layouts, in the sense, that on the right side, create a JPanel with BorderLayout, put a JPanel(say compPanel) at the CENTER and a JPanel(say buttonPanel) at PAGE_END location. Now use a new JPanel(say panel) with GridLayout and put all the components on it, and place this compPanel inside centerPanel. Place JButton(button4) inside buttonPanel as is.

BoxLayout on the contrary, respects the preferred size of a given JComponent, which is usually calculated based on the content the JComponent holds or given explicity, hence components do not tend to align well with respect to other given components.

Here is the working example :

import java.awt.*;
import javax.swing.*;

public class Testy extends JPanel {        

    private JPanel panel;
    private JPanel buttonPanel;

    public Testy() {
        setLayout(new BorderLayout(5, 5));

        JPanel compPanel = new JPanel();
        panel = new JPanel(new GridLayout(6, 1, 5, 5));     
        JButton button = new JButton("Button ...... 1");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        panel.add(button);

        button = new JButton("Button 2");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        panel.add(button);

        button = new JButton("Button ........... 3");
        //button.setPreferredSize(...);
        //button.setMaximumSize(...);
        panel.add(button);

        JLabel label = new JLabel("Label");
        //label.setPreferredSize(...);
        //label.setMaximumSize(...);
        panel.add(label);

        JTextField textField = new JTextField();
        //textField.setPreferredSize(...);
        //textField.setMaximumSize(...);
        panel.add(textField);
        compPanel.add(panel);

        buttonPanel = new JPanel();
        button = new JButton("Button 4");
        buttonPanel.add(button);

        add(compPanel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.PAGE_END);
    }

    private void constructGUI() {
        JFrame frame = new JFrame("Testy");
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        JPanel centerPanel = new JPanel();
        frame.getContentPane().setLayout(new BorderLayout(5, 5));
        centerPanel.setBackground(Color.DARK_GRAY);
        frame.add(centerPanel, BorderLayout.CENTER);

        frame.add(this, BorderLayout.LINE_END);

        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Testy().constructGUI();
            }
        });
    }
}

OUTPUT :

LAYOUT EXAMPLE