Question

I am trying to create a form in Swing.

The form should look similar to this:

 ____________________________________
|___________________________________X|
|                                    |
|              ________________      |
|      label1 [________________]     |
|              ________________      |
|      label2 [________________]     |
|                                    |
|                                    |
|                     [Save] [Close] |
|____________________________________|

But I'm having trouble center aligning the text fields vertically.

Below is the code for opening the frame:

public class Main {

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                LayoutTest test = new LayoutTest();
                test.setVisible(true);
            }
        });
    }
}

Here is the code for initialing the fields and creating the layout:

public class LayoutTest {
    private JFrame testFrame;

    JLabel label1;
    JTextField field1;

    JLabel label2;
    JTextField field2;

    JButton saveButton;
    JButton closeButton;

    public LayoutTest() {
        testFrame = new JFrame();

        initProperties();
        initContent();
        initLayout();
    }

    private void initProperties() {
        testFrame.setTitle("Test");
        testFrame.setSize(1000, 800);
        testFrame.setLocationRelativeTo(null);
        testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }

    private void initContent() {
        label1= new JLabel("Label 1");
        field1= new JTextField(25);
        label1.setLabelFor(field1);

        label2= new JLabel("Label 2");
        field2= new JTextField(25);
        label2.setLabelFor(field2);

        saveButton = new JButton("Save");

        closeButton = new JButton("Close");
        closeButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                System.exit(0);
            }
        });

        testFrame.add(label1);
        testFrame.add(field1);
        testFrame.add(label2);
        testFrame.add(field2);
        testFrame.add(saveButton);
        testFrame.add(closeButton);
    }

    private void initLayout() {
        SpringLayout layout = new SpringLayout();

        layout.putConstraint(SpringLayout.NORTH, label1, 10, SpringLayout.NORTH, testFrame.getContentPane());
        layout.putConstraint(SpringLayout.EAST, label1, -5, SpringLayout.WEST, field1);

        layout.putConstraint(SpringLayout.NORTH, field1, 10, SpringLayout.NORTH, testFrame.getContentPane());
        layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, field1, -10, SpringLayout.HORIZONTAL_CENTER, testFrame.getContentPane());

        layout.putConstraint(SpringLayout.NORTH, label2, 10, SpringLayout.SOUTH, label1);
        layout.putConstraint(SpringLayout.EAST, label2, -5, SpringLayout.WEST, field2);

        layout.putConstraint(SpringLayout.NORTH, field2, 5, SpringLayout.SOUTH, field1);
        layout.putConstraint(SpringLayout.HORIZONTAL_CENTER, field2, -10, SpringLayout.HORIZONTAL_CENTER, testFrame.getContentPane());


        layout.putConstraint(SpringLayout.SOUTH, closeButton, -20, SpringLayout.SOUTH, testFrame.getContentPane());
        layout.putConstraint(SpringLayout.EAST, closeButton, -20, SpringLayout.EAST, testFrame.getContentPane());

        layout.putConstraint(SpringLayout.SOUTH, saveButton, -20, SpringLayout.SOUTH, testFrame.getContentPane());
        layout.putConstraint(SpringLayout.EAST, saveButton, -10, SpringLayout.WEST, closeButton);

        testFrame.setLayout(layout);
    }

    public void setVisible(boolean visible) {
        testFrame.setVisible(visible);
    }
}

I've tried to add the fields to a panel and then use SpringLayout.VERTICAL_CENTER on the panel but nothing showed up.

How can I center align the fields as a group?

Was it helpful?

Solution 2

You have any number of options depending on your needs. I prefer GridBagLayout, but that's cause I've been using for 15 years.

Dialog 01

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class FormLayout {

    public static void main(String[] args) {
        new FormLayout();
    }

    public FormLayout() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(8, 8, 8, 8);
            gbc.anchor = GridBagConstraints.EAST;

            add(new JLabel("Label 1"), gbc);
            gbc.gridy++;
            add(new JLabel("Label 2"), gbc);

            gbc.anchor = GridBagConstraints.WEST;
            gbc.gridy = 0;
            gbc.gridx++;
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            add(new JTextField(20), gbc);
            gbc.gridy++;
            add(new JTextField(20), gbc);

            gbc.gridy++;
            gbc.gridx++;
            gbc.gridwidth = 1;
            gbc.anchor = GridBagConstraints.EAST;
            gbc.weightx = 1;
            add(new JButton("Save"), gbc);
            gbc.weightx = 0;
            gbc.gridx++;
            add(new JButton("Close"), gbc);
        }           
    }        
}

The problem with this, for me, is the buttons will stay in the middle of form, near the fields, as the window is resized

You might not mind this, but it annoys me. I'd prefer to use a compound layout approaching, placing the content in a separate panel and the buttons in another. It means I get to use the power of three layout managers instead of just one...

Compound layout

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class FormLayout {

    public static void main(String[] args) {
        new FormLayout();
    }

    public FormLayout() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {

            setLayout(new BorderLayout());

            JPanel content = new JPanel(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(8, 8, 8, 8);
            gbc.anchor = GridBagConstraints.EAST;

            content.add(new JLabel("Label 1"), gbc);
            gbc.gridy++;
            content.add(new JLabel("Label 2"), gbc);

            gbc.anchor = GridBagConstraints.WEST;
            gbc.gridy = 0;
            gbc.gridx++;
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            content.add(new JTextField(20), gbc);
            gbc.gridy++;
            content.add(new JTextField(20), gbc);

            JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT));    
            buttons.add(new JButton("Save"));
            buttons.add(new JButton("Close"));

            add(content);
            add(buttons, BorderLayout.SOUTH);
        }            
    }        
}

The choice however, is your own...

OTHER TIPS

Use nested panels. Something like:

JPanel springPanel = new JPanel(...);
springPanel.add(...);

JPanel center = new JPanel( new GridBagLayout() );
center.add(springPanel, new GridBagConstraints() );

frame.add( center );
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top