13

When my application loads, which is made using netbeans, the first JTextField is automatically focused, and in this JTextField, I have written "Enter your Username", it will go away when the user clicks on this field, but when the application is loaded, this field is focused, means I can't see "Enter your Username", how to unfocus it on startup ?

Asif
  • 4,980
  • 8
  • 38
  • 53
Ali Bassam
  • 9,691
  • 23
  • 67
  • 117
  • Theres 2 JTextFields, first for username, second for password, and a JMenuItem called Log in, the moment I run the application, the first JTextField is focused, I don't want that – Ali Bassam May 27 '12 at 10:21
  • BTW - if the user name for each app. installation is *expected* to be constant, just populate the user name field with the default & let the user tab to the next field if correct. If it is *guaranteed* to be constant, populate the field and disable it. It will not **be** focusable, & the focus will go to the 2nd field by default. – Andrew Thompson May 27 '12 at 10:27

4 Answers4

14

A log-in would be best done in a modal dialog, but that introduces problems in that the method requestFocusInWindow() must be called after the component is visible, but that is blocked by the fact the dialog is modal!

This example uses Rob Camick's RequestFocusListener (as presented in Dialog Focus) to manage focus after the dialog is visible.

Login with focused password field

Note: That is how it appears before the user does anything. The password field is focused by default.

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

public class LoginRequired {

    LoginRequired() {
        JFrame f = new JFrame("Login Required");
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        f.setResizable(false);
        f.setSize(400, 300); // not recommended, but used here for convenience
        f.setLocationByPlatform(true);
        f.setVisible(true);

        showLogin(f);
    }

    private void showLogin(JFrame frame) {
        JPanel p = new JPanel(new BorderLayout(5,5));

        JPanel labels = new JPanel(new GridLayout(0,1,2,2));
        labels.add(new JLabel("User Name", SwingConstants.TRAILING));
        labels.add(new JLabel("Password", SwingConstants.TRAILING));
        p.add(labels, BorderLayout.LINE_START);

        JPanel controls = new JPanel(new GridLayout(0,1,2,2));
        JTextField username = new JTextField("Joe Blogs");
        controls.add(username);
        JPasswordField password = new JPasswordField();
        password.addAncestorListener(new RequestFocusListener(false));
        controls.add(password);
        p.add(controls, BorderLayout.CENTER);

        JOptionPane.showMessageDialog(
            frame, p, "Log In", JOptionPane.QUESTION_MESSAGE);
        System.out.println("User Name: " + username.getText());
        System.out.println("Password: " + new String(password.getPassword()));
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new LoginRequired();
        });
    }
}

/**
 *  Convenience class to request focus on a component.
 *
 *  When the component is added to a realized Window then component will
 *  request focus immediately, since the ancestorAdded event is fired
 *  immediately.
 *
 *  When the component is added to a non realized Window, then the focus
 *  request will be made once the window is realized, since the
 *  ancestorAdded event will not be fired until then.
 *
 *  Using the default constructor will cause the listener to be removed
 *  from the component once the AncestorEvent is generated. A second constructor
 *  allows you to specify a boolean value of false to prevent the
 *  AncestorListener from being removed when the event is generated. This will
 *  allow you to reuse the listener each time the event is generated.
 */
class RequestFocusListener implements AncestorListener
{
    private boolean removeListener;

    /*
     *  Convenience constructor. The listener is only used once and then it is
     *  removed from the component.
     */
    public RequestFocusListener()
    {
        this(true);
    }

    /*
     *  Constructor that controls whether this listen can be used once or
     *  multiple times.
     *
     *  @param removeListener when true this listener is only invoked once
     *                        otherwise it can be invoked multiple times.
     */
    public RequestFocusListener(boolean removeListener)
    {
        this.removeListener = removeListener;
    }

    @Override
    public void ancestorAdded(AncestorEvent e)
    {
        JComponent component = e.getComponent();
        component.requestFocusInWindow();

        if (removeListener)
            component.removeAncestorListener( this );
    }

    @Override
    public void ancestorMoved(AncestorEvent e) {}

    @Override
    public void ancestorRemoved(AncestorEvent e) {}
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
5
textField.setFocusable(false);
textField.setFocusable(true);

If, and only if, textField had focus, the next component in TAB-order order will get focus automatically. The effect is the same as a TAB press.

(not tested in a GUI with just one focusable component :) )

Mark Jeronimus
  • 9,278
  • 3
  • 37
  • 50
4

Use requestFocusInWindow() to set focus on some other component rather then your JTextfield first.

But i'd suggest not to alter the native focus system, rather setText(String s) on the JTextField after initComponents() call in the constructor (assumed to be in netbeans).

Further optional reading: How to Use the Focus Subsystem

Asif
  • 4,980
  • 8
  • 38
  • 53
  • What if I had to click a JMenuItem to Log in ? I used requestFocusInWindow() on another element, but the moment I click on that JMenuItem, the JTextField is focused, the second time I click on that JMenuItem, the JTextField is not focused, it works later, but first time no – Ali Bassam May 27 '12 at 10:16
  • Do you try `nextFocusableComponent` property in NetBeans property editor for your `JMenuItem`? – Asif May 27 '12 at 10:20
  • I fixed it, I used ur code twice, on startup, and when I click on the Jmenuitem, thanks – Ali Bassam May 27 '12 at 10:25
4

I think giving keyboard focus to the username field is the correct behavior, assuming that's what the user needs to do first. Instead of clearing on focus, why not clear only after the user types something?:

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

public class PlaceholderTextField extends JTextField {

    public static void main(final String[] args) {
        final PlaceholderTextField tf = new PlaceholderTextField("");
        tf.setColumns(20);
        tf.setPlaceholder("All your base are belong to us!");
        final Font f = tf.getFont();
        tf.setFont(new Font(f.getName(), f.getStyle(), 30));
        JOptionPane.showMessageDialog(null, tf);
    }

    private String placeholder;

    public PlaceholderTextField() {
    }

    public PlaceholderTextField(
        final Document pDoc,
        final String pText,
        final int pColumns)
    {
        super(pDoc, pText, pColumns);
    }

    public PlaceholderTextField(final int pColumns) {
        super(pColumns);
    }

    public PlaceholderTextField(final String pText) {
        super(pText);
    }

    public PlaceholderTextField(final String pText, final int pColumns) {
        super(pText, pColumns);
    }

    public String getPlaceholder() {
        return placeholder;
    }

    @Override
    protected void paintComponent(final Graphics pG) {
        super.paintComponent(pG);

        if (placeholder.length() == 0 || getText().length() > 0) {
            return;
        }

        final Graphics2D g = (Graphics2D) pG;
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        g.setColor(getDisabledTextColor());
        g.drawString(placeholder, getInsets().left, pG.getFontMetrics()
            .getMaxAscent() + getInsets().top);
    }

    public void setPlaceholder(final String s) {
        placeholder = s;
    }

}

If you really just want to remove focus, some options:

  • component.setFocusable(false);
  • KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
  • KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
Peter Tseng
  • 13,613
  • 4
  • 67
  • 57