1

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();
            }
        });
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
erp
  • 2,950
  • 9
  • 45
  • 90
  • 1
    The main culprit is the `AbsoluteLayout` here, and other not providing the columns for the `JTextField` in question. Do `JTextField tField = new JTextField(10)`, that will be enough to set it's size :-) – nIcE cOw Jul 23 '14 at 15:40
  • To get help with layouts, provide ASCII art or a simple drawing of how the GUI should appear at default size and (if resizable) with extra width/height. – Andrew Thompson Jul 24 '14 at 13:12

2 Answers2

3
  1. Don't use null layouts!!!! Don't use setSize() or setLocation(). It is the job of the layout manager to determine the size/location of a component. Swing was designed to be used with layout managers.

  2. When creating a JTextField use something like JTextField textField = new JTextField(10) to specify the number of characters the text field can base its preferred size on. Now the layout manager can do its job.

Since it appears you want to position the components vertically you might be able to use a BoxLayout or GridBagLayout. Read the Swing tutorial on Using Layout Managers for more information and working examples.

camickr
  • 321,443
  • 19
  • 166
  • 288
2

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.)

Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77