Search code examples
javaswingjtextfieldlayout-managernull-layout-manager

Jtextfield begins in a smaller state


I am making an example application just to learn basics. I am having a problem where I have 3 JTextFields and when I launch the application the bottom 2 JTextFields do not show up, but the first one which has the focus, does. But only a fraction of the final size i intend. When I click on them however or begin to type in the fields they expand to the size i originally intended.

They are all in the correct location though they are showing up incorrectly at launch. Any ideas?

package password;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class password implements  ActionListener{
    static int width = 220, height = 250;

    JPanel textPanel, panelForTextFields, completionPanel;
    JLabel serviceLabel, usernameLabel, passwordLabel;
    JTextField serviceField, usernameField, passwordField;
    JButton Submit;

    public JPanel setupPane (){

        // We create a bottom JPanel to place everything on.
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(null);

        textPanel = new JPanel();
        textPanel.setLayout(null);
        textPanel.setLocation(0, 0);
        textPanel.setSize(width, height);
        mainPanel.add(textPanel);

        panelForTextFields = new JPanel();
        panelForTextFields.setLayout(null);
        panelForTextFields.setLocation(0, 0);
        panelForTextFields.setSize(width, height);
        mainPanel.add(panelForTextFields);

        //---------------------------------------------------------------------------------------------------------------------------------
        //                                              Service text field and label
        //---------------------------------------------------------------------------------------------------------------------------------

        serviceLabel = new JLabel("Service:");
        serviceLabel.setLocation(60, 0);
        serviceLabel.setSize(80, 40);
        textPanel.add(serviceLabel);

        serviceField = new JTextField();
        serviceField.setLocation(60, 30);
        serviceField.setSize(100, 20);
        panelForTextFields.add(serviceField);

        //---------------------------------------------------------------------------------------------------------------------------------
        //                                              Username text field and label
        //---------------------------------------------------------------------------------------------------------------------------------

        usernameLabel = new JLabel("Username:");
        usernameLabel.setLocation(60, 45);
        usernameLabel.setSize(80, 40);
        textPanel.add(usernameLabel);

        usernameField = new JTextField();
        usernameField.setLocation(60, 75);
        usernameField.setSize(100, 20);
        panelForTextFields.add(usernameField);

        //---------------------------------------------------------------------------------------------------------------------------------
        //                                              Password text field and label
        //---------------------------------------------------------------------------------------------------------------------------------

        passwordLabel = new JLabel("Password:");
        passwordLabel.setLocation(60, 90);
        passwordLabel.setSize(80, 40);
        textPanel.add(passwordLabel);

        passwordField = new JTextField();
        passwordField.setLocation(60, 120);
        passwordField.setSize(100, 20);
        panelForTextFields.add(passwordField);

        //---------------------------------------------------------------------------------------------------------------------------------
        //                                                      Submit button
        //---------------------------------------------------------------------------------------------------------------------------------        

        Submit = new JButton("Submit");
        Submit.setLocation(60, 165);
        Submit.setSize(100, 20);
        panelForTextFields.add(Submit);
        Submit.addActionListener(this);

        return mainPanel;
    }

    public void actionPerformed(ActionEvent e) {

        Object source = e.getSource();
        if(source == Submit) {
            JOptionPane.showMessageDialog(null," information added.","Success!", JOptionPane.PLAIN_MESSAGE);
        }
    }

    private static void password() {    
        JFrame mainF = new JFrame("Password Application");

        password demo = new password();
        mainF.setContentPane(demo.setupPane());
        mainF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainF.setSize(width, height);
        mainF.setResizable(false);
        mainF.setVisible(true);
    }

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

Solution

  • Look at your example as a lesson of how not to build your layouts.

    Absolute positioning cannot cope with various challenges that Java GUI applications face:

    • font changes
    • (human) language switches
    • different screen resolutions
    • changes in DPI
    • various operating systems and their layout standards

    Therefore, programmers need to use layout managers. Over the years, multiple layout managers were created for Swing. I recommend the following three (in that particular order):

    1. MigLayout
    2. GroupLayout
    3. FormLayout

    MigLayout and FormLayout are third-party managers. Therefore, we need to download and add their libraries to our projects. These three managers are most flexible and powerful of all managers.

    I create your simple layout with all these three managers.

    MigLayout

    MigLayout has a rich set of tools to build the required layout.

    package com.zetcode;
    
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JTextField;
    import net.miginfocom.swing.MigLayout;
    
    
    public class MigLayoutPassword extends JFrame {
    
        public MigLayoutPassword() {
    
            initUI();
    
            setTitle("Password application");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
        }
    
        private void initUI() {
    
            JPanel pnl = new JPanel(new MigLayout("wrap 2, ins dialog", 
                    "[right][grow]"));
    
            JLabel serviceLbl = new JLabel("Service:");
            JLabel userNameLbl = new JLabel("User name:");
            JLabel passwordLbl = new JLabel("Password:");
    
            JTextField field1 = new JTextField(10);
            JTextField field2 = new JTextField(10);
            JPasswordField field3 = new JPasswordField(10);
    
            pnl.add(serviceLbl);
            pnl.add(field1, "growx");
    
            pnl.add(userNameLbl);
            pnl.add(field2, "growx");
    
            pnl.add(passwordLbl);
            pnl.add(field3, "growx");
    
            add(pnl);
    
            pack();
    
        }
    
        public static void main(String[] args) {
    
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    MigLayoutPassword ex = new MigLayoutPassword();
                    ex.setVisible(true);
                }
            });
        }
    }
    

    Note that there is no positioning, no explicit size setting of components. This is handled by the manager. There are only a few lines that do the layout. Changes to the layout are done easily and quickly.

    JPanel pnl = new JPanel(new MigLayout("wrap 2, ins dialog", 
            "[right][grow]"));
    

    Note the dialog keyword. This keyword is translated to standard space around the borders for the current platform.

    MigLayout Password

    GroupLayout

    In constrast to MigLayout, GroupLayout has only a few tools to influence the layout. However, it is suprisingly powerful. In this manager, we define the layout using groups of components for each dimension separately.

    package com.zetcode;
    
    import java.awt.Container;
    import java.awt.EventQueue;
    import javax.swing.GroupLayout;
    import static javax.swing.GroupLayout.Alignment.BASELINE;
    import static javax.swing.GroupLayout.Alignment.TRAILING;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JTextField;
    
    
    public class GroupLayoutPassword extends JFrame {
    
        public GroupLayoutPassword() {
    
            initUI();
    
            setTitle("Password application");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
        }
    
        private void initUI() {
    
            Container pane = getContentPane();
            GroupLayout gl = new GroupLayout(pane);
            pane.setLayout(gl);
    
            JLabel serviceLbl = new JLabel("Service:");
            JLabel userNameLbl = new JLabel("User name:");
            JLabel passwordLbl = new JLabel("Password:");
    
            JTextField field1 = new JTextField(10);
            JTextField field2 = new JTextField(10);
            JTextField field3 = new JTextField(10);
    
            gl.setAutoCreateGaps(true);
            gl.setAutoCreateContainerGaps(true);   
    
            gl.setHorizontalGroup(gl.createSequentialGroup()
                    .addGroup(gl.createParallelGroup(TRAILING)
                            .addComponent(serviceLbl)
                            .addComponent(userNameLbl)
                            .addComponent(passwordLbl))
                    .addGroup(gl.createParallelGroup()
                            .addComponent(field1)
                            .addComponent(field2)
                            .addComponent(field3))
            );        
    
            gl.setVerticalGroup(gl.createSequentialGroup()
                    .addGroup(gl.createParallelGroup(BASELINE)
                            .addComponent(serviceLbl)
                            .addComponent(field1))
                    .addGroup(gl.createParallelGroup(BASELINE)
                            .addComponent(userNameLbl)
                            .addComponent(field2))
                    .addGroup(gl.createParallelGroup(BASELINE)
                            .addComponent(passwordLbl)
                            .addComponent(field3))
            );
    
            pack();
        }
    
        public static void main(String[] args) {
    
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    GroupLayoutPassword ex = new GroupLayoutPassword();
                    ex.setVisible(true);
                }
            });
        }
    }
    

    FormLayout

    To create this simple layout, I have used the high-level DefaultFormBuilder. For more complicated layouts, we would need to go without this (or similar) builder.

    package com.zetcode;
    
    import com.jgoodies.forms.builder.DefaultFormBuilder;
    import com.jgoodies.forms.factories.Borders;
    import com.jgoodies.forms.layout.FormLayout;
    import java.awt.EventQueue;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JTextField;
    
    
    public class FormLayoutPassword extends JFrame {
    
        public FormLayoutPassword() {
    
            initUI();
    
            setTitle("Password application");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
        }
    
        private void initUI() {
    
            FormLayout fl = new FormLayout(
                "r:p, $rg, p:g", // columns
                "");  // rows
    
            DefaultFormBuilder builder = new DefaultFormBuilder(fl);
            builder.border(Borders.DIALOG); 
    
            JTextField field1 = new JTextField(10);
            JTextField field2 = new JTextField(10);
            JPasswordField field3 = new JPasswordField(10);        
    
            builder.append("&Service: ", field1);
            builder.nextLine();
    
            builder.append("&User name: ", field2);
            builder.nextLine();
    
            builder.append("&Password: ", field3);
            builder.nextLine();
    
            JPanel pnl = builder.getPanel();
            setContentPane(pnl);
    
            pack();
    
        }
    
        public static void main(String[] args) {
    
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    FormLayoutPassword ex = new FormLayoutPassword();
                    ex.setVisible(true);
                }
            });
        }
    }
    

    Again, we see no explicit positioning or setting size of components or gaps.

        FormLayout fl = new FormLayout(
            "r:p, $rg, p:g", // columns
            "");  // rows
    

    All three managers use the concept of related gaps, specified here as $rg. A related gap is an abstraction over a rigid pixel gap size. (A rigid gap specified in pixels is hardware and OS dependent.)