Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically set focus on JTextField

Cant find an answer for this (or most likely Im not asking properly).

How can I set focus on JTextField textfield1 as soon as my JFrame is initiated? by focus I mean the user can start typing right away without having to click on the JTextField.

I tried textfield1.setCaretPosition(0) and textfield1.moveCaretPosition(0), neither worked.

Also the focus stays on the submit button after clicking it (even if I call the above 2 after the click).

like image 219
Cody Avatar asked Jan 12 '23 19:01

Cody


2 Answers

Focus is controlled in a number of ways in Swing, but in your case, the simplest might be to simply use JTextField#requestFocusInWindow

It's a little off topic, but you might want to take a look at How to use the a Focus Subsystem

like image 195
MadProgrammer Avatar answered Jan 23 '23 02:01

MadProgrammer


A bit more fun than directly requesting the focus on the initial component is a custom FocusTraversalPolicy implementing a general mechanism to lookup/configure the default. The basic notions are already available in its api, having methods for returning the initial/defaultComponent, f.i.:

public abstract Component getDefaultComponent(Container aContainer)

Returns the default Component to focus. This Component will be the first to receive focus when traversing down into a new focus traversal cycle rooted at aContainer.

The default implementation returns the first component in the cycle, a custom implementation might look for a custom indicator, f.i. a client property. Simple usage would set that policy to the frame which has the marker in its contentPane, something like:

// a custom policy checking for the property
FocusTraversalPolicy policy = new LayoutFocusTraversalPolicy() {

    @Override
    public Component getDefaultComponent(Container aContainer) {
        if (aContainer instanceof JComponent) {
            JComponent parent = (JComponent) aContainer;
            if (parent.getClientProperty("defaultFocus") instanceof Component) {
                return (Component) parent.getClientProperty("defaultFocus");
            }
        }
        if (aContainer instanceof RootPaneContainer) {
            RootPaneContainer root = (RootPaneContainer) aContainer;
            JComponent parent = (JComponent) root.getContentPane();
            if (parent.getClientProperty("defaultFocus") instanceof Component) {
                return (Component) parent.getClientProperty("defaultFocus");
            }

        }
        return super.getDefaultComponent(aContainer);
    }

};
JFrame frame = ... // create  and fill
JTextField field = new JTextField(20);
frame.add(field, BorderLayout.SOUTH);
// set the client property 
((JComponent) frame.getContentPane()).putClientProperty("defaultFocus", field);
// set the custom policy
frame.setFocusTraversalPolicy(policy);

A bit more elegant would be to use such a policy by default - that can be achieved by installing it as the default policy of the KeyboardFocusManager. With that in place the usage would be simplified to

  • install the custom default once early in the application life-cycle
  • mark the initial focus component (no need to manually set the frame's policy)

Code:

// very early in the application code
initializeDefaultFocusTraversalPolicy();

// default in any frame
JFrame frame = ... // create  and fill
JTextField field = new JTextField(20);
frame.add(field, BorderLayout.SOUTH);
// set the client property 
((JComponent) frame.getContentPane())
    .putClientProperty(DelegatingFocusTraversalPolicy.DEFAULT_FOCUS_KEY, field);

Swing wouldn't be Swing it there weren't a catch, though:

  • the frame's default policy is internally set on its instantiation - so it's not a big surprise that the keyboardFocusManager has to be configured before the frame is created
  • the UIManager has its own ideas about the manager's default, in fact uncondionally configures it when the very first frame is created (which overwrites our own default)

The way out is to create a dummy frame and then set the policy:

public static void initializeDefaultFocusTraversalPolicy() {
    // a custom default policy is overwritten by the UIManager the
    // very first time it sees a top-level container created
    // it does so  unconditionally depending on a flag in LAFState
    // see UIManager.maybeInitializeFocusPolicy
    // so we tricks him into doing it for a fake frame
    new JFrame();
    // and set our custom default afterwards
    FocusTraversalPolicy p = KeyboardFocusManager.getCurrentKeyboardFocusManager()
         .getDefaultFocusTraversalPolicy();
    KeyboardFocusManager.getCurrentKeyboardFocusManager()
         .setDefaultFocusTraversalPolicy(new CustomFocusTraversalPolicy(p));
}

/**
 * Basically the same custom policy as the ad-hoc above, just with
 * delegating 
 */
public static class CustomFocusTraversalPolicy extends FocusTraversalPolicy {
    public static final String DEFAULT_FOCUS_KEY = "defaultFocus";
    private FocusTraversalPolicy delegate;

    public CustomFocusTraversalPolicy(FocusTraversalPolicy delegate) {
        this.delegate = Contract.asNotNull(delegate, "the delegate must not be null");
    }

    @Override
    public Component getDefaultComponent(Container container) {
        if (container instanceof JComponent) {
            JComponent parent = (JComponent) container;
            if (parent.getClientProperty(DEFAULT_FOCUS_KEY) instanceof Component) {
                return (Component) parent.getClientProperty(DEFAULT_FOCUS_KEY);
            }
        }
        if (container instanceof RootPaneContainer) {
            RootPaneContainer root = (RootPaneContainer) container;
            JComponent parent = (JComponent) root.getContentPane();
            if (parent.getClientProperty(DEFAULT_FOCUS_KEY) instanceof Component) {
                return (Component) parent.getClientProperty(DEFAULT_FOCUS_KEY);
            }

        }
        return delegate.getDefaultComponent(container);
    }
    @Override
    public Component getComponentAfter(Container aContainer,
            Component aComponent) {
        return delegate.getComponentAfter(aContainer, aComponent);
    }

    @Override
    public Component getComponentBefore(Container aContainer,
            Component aComponent) {
        return delegate.getComponentBefore(aContainer, aComponent);
    }

    @Override
    public Component getFirstComponent(Container aContainer) {
        return delegate.getFirstComponent(aContainer);
    }

    @Override
    public Component getLastComponent(Container aContainer) {
        return delegate.getLastComponent(aContainer);
    }
}
like image 41
kleopatra Avatar answered Jan 23 '23 04:01

kleopatra