Автоматически устанавливать фокус на JTextField

Не могу найти ответ на этот вопрос (или, скорее всего, я не правильно спрашиваю).

Как я могу установить фокус на JTextField textfield1, как только мой JFrame будет инициирован? под фокусом я подразумеваю, что пользователь может сразу начать печатать, не нажимая на JTextField.

Я пробовал textfield1.setCaretPosition(0) и textfield1.moveCaretPosition(0), ни один не работал.

Также фокус остается на кнопке отправки после ее нажатия (даже если я вызываю 2 выше после нажатия).


person Cody    schedule 01.12.2013    source источник
comment
См. JComponent.requestFocusInWindow(). .   -  person Andrew Thompson    schedule 01.12.2013
comment
Вы пробовали textField1.requestFocusInWindow();?   -  person paulsm4    schedule 01.12.2013
comment
возможный дубликат Полноэкранные кадры Swing неправильно фокусируются в Linux (подойдет Windows)   -  person Andrew Thompson    schedule 01.12.2013
comment
спасибо, я пытался искать в Google, но не думал, что слово «фокус» подходит для этого.   -  person Cody    schedule 01.12.2013


Ответы (2)


Фокус управляется несколькими способами в Swing, но в вашем случае самым простым может быть простое использование JTextField#requestFocusInWindow

Это немного не по теме, но вы можете взглянуть на Как использовать подсистему фокуса

person MadProgrammer    schedule 01.12.2013
comment
как только мой JFrame будет инициирован? == завернутый в invokeLater - person mKorbel; 01.12.2013

Немного больше удовольствия, чем прямой запрос фокуса на начальный компонент, представляет собой пользовательская FocusTraversalPolicy, реализующая общий механизм для поиска/настройки значения по умолчанию. Базовые понятия уже доступны в его API, есть методы для возврата исходного/дефолтногоКомпонента, т.е.:

общедоступный абстрактный компонент getDefaultComponent (контейнер aContainer)

Возвращает компонент по умолчанию для фокуса. Этот компонент будет первым, кто получит фокус при переходе вниз в новый цикл обхода фокуса с корнем в контейнере.

Реализация по умолчанию возвращает первый компонент в цикле, пользовательская реализация может искать пользовательский индикатор, т.е. свойство клиента. Простое использование установило бы эту политику для фрейма, у которого есть маркер в его области содержимого, что-то вроде:

// 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);

Немного более элегантно было бы использовать такую ​​политику по умолчанию — этого можно добиться, установив ее в качестве политики по умолчанию для KeyboardFocusManager. При этом использование будет упрощено до

  • установить пользовательское значение по умолчанию один раз в начале жизненного цикла приложения
  • отметьте начальный компонент фокуса (нет необходимости вручную устанавливать политику фрейма)

Код:

// 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 не был бы Swing, если бы не было подвоха:

  • политика фрейма по умолчанию устанавливается при его создании, поэтому неудивительно, что keyboardFocusManager необходимо настроить до создания фрейма.
  • UIManager имеет свои представления о дефолте менеджера, фактически безоговорочно настраивает его при создании самого первого фрейма (который перезаписывает наш собственный дефолт)

Выход — создать фиктивный фрейм, а затем установить политику:

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);
    }
}
person kleopatra    schedule 01.12.2013