Немного больше удовольствия, чем прямой запрос фокуса на начальный компонент, представляет собой пользовательская 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
JComponent.requestFocusInWindow()
. . - person Andrew Thompson   schedule 01.12.2013textField1.requestFocusInWindow();
? - person paulsm4   schedule 01.12.2013