Search code examples
javaswinglayout-managerboxlayout

BoxLayout: can't setup child component size


I have a JFrame - SuperTest and JPanel - SuperLogin. The login panel has the username and password input fields and a login button. I want it to look like this:

enter image description here

but it looks like the pic below, with input fields having too huge height and width.

SuperTest.java:

import javax.swing.*;

public class SuperTest extends JFrame {
    public SuperTest()  {
        add(new SuperLogin());
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(600, 400);
    }

    public static void main(String[] args) {
        SuperTest test = new SuperTest();
    }
}

SuperLogin.java:

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

public class SuperLogin extends JPanel {
    private JButton loginButton =
            new JButton("Login");
    private TextField usernameField =
            new TextField();
    private TextField passwordField =
            new TextField();

    public SuperLogin()  {
        BoxLayout layout =
                new BoxLayout(this, BoxLayout.Y_AXIS);
        setLayout(layout);

        add(new JLabel("Login"));

        add(usernameField);
        add(passwordField);
        add(loginButton);

        componentSetup();
    }

    private void componentSetup()  {
        loginButton.setSize(20, 10);
        usernameField.setSize(100, 50);
        passwordField.setSize(100, 50);

        loginButton.setMinimumSize(new Dimension(20, 10));
        usernameField.setMinimumSize(new Dimension(100, 50));
        passwordField.setMinimumSize(new Dimension(100, 50));

        loginButton.setPreferredSize(new Dimension(20, 10));
        usernameField.setPreferredSize(new Dimension(100, 50));
        passwordField.setPreferredSize(new Dimension(100, 50));

    }
}

I read that setting min, preferred size would be enough, but it looks like it's not.

enter image description here


Solution

  • I put everything into a single class. Explanations after the code.

    import java.awt.Component;
    import java.awt.EventQueue;
    
    import javax.swing.BorderFactory;
    import javax.swing.Box;
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JTextField;
    import javax.swing.WindowConstants;
    
    public class SuperOne implements Runnable {
        private JButton  loginButton;
        private JFrame  frame;
        private JPasswordField  passwordField;
        private JTextField  usernameField;
    
        @Override
        public void run() {
            showGui();
        }
    
        private JPanel createLoginPanel() {
            JPanel loginPanel = new JPanel();
            BoxLayout layout = new BoxLayout(loginPanel, BoxLayout.PAGE_AXIS);
            loginPanel.setLayout(layout);
            loginPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
            JLabel loginLabel = new JLabel("Login");
            loginLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
            usernameField = new JTextField(10);
            usernameField.setAlignmentX(Component.CENTER_ALIGNMENT);
            passwordField = new JPasswordField(10);
            passwordField.setAlignmentX(Component.CENTER_ALIGNMENT);
            loginButton = new JButton("login");
            loginButton.setAlignmentX(Component.CENTER_ALIGNMENT);
            loginPanel.add(loginLabel);
            loginPanel.add(Box.createVerticalStrut(15));
            loginPanel.add(usernameField);
            loginPanel.add(Box.createVerticalStrut(5));
            loginPanel.add(passwordField);
            loginPanel.add(Box.createVerticalStrut(5));
            loginPanel.add(loginButton);
            return loginPanel;
        }
    
        private void showGui() {
            frame = new JFrame();
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.add(createLoginPanel());
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        /**
         * Start here.
         */
        public static void main(String[] args) {
            EventQueue.invokeLater(new SuperOne());
        }
    }
    
    1. All code that deals with the GUI components must run on the Event Dispatch Thread (EDT). Although not mandatory, I like to explicitly launch the EDT by calling EventQueue.invokeLater().
    2. Refer to the Web page with the tutorial on BoxLayout that appears in the other answer.
    3. JTextField and JPasswordField both have a columns property. I find that better for setting a desired width than using setPreferredSize()

    Here is a screen capture of the running app.

    enter image description here