【问题标题】:Automatically set focus on JTextField自动在 JTextField 上设置焦点
【发布时间】:2024-12-08 01:10:02
【问题描述】:

找不到这个问题的答案(或者很可能我没有正确询问)。

我的JFrame 启动后,如何将焦点集中在JTextField textfield1? 焦点是指用户无需点击JTextField即可立即开始输入。

我试过textfield1.setCaretPosition(0)textfield1.moveCaretPosition(0),都没有成功。

点击后焦点仍停留在提交按钮上(即使我在点击后调用上述2)。

【问题讨论】:

标签: java swing jframe jtextfield caret


【解决方案1】:

在 Swing 中以多种方式控制焦点,但在您的情况下,最简单的可能是简单地使用 JTextField#requestFocusInWindow

这有点离题,但你可能想看看How to use the a Focus Subsystem

【讨论】:

  • 我的 JFrame 启动后? == 包裹在 invokeLater 中
【解决方案2】:

比直接请求关注初始组件更有趣的是自定义 FocusTraversalPolicy 实现了查找/配置默认值的通用机制。基本概念已经在其 api 中可用,具有返回初始/默认组件的方法,f.i.:

公共抽象组件getDefaultComponent(Container aContainer)

将默认组件返回为焦点。该组件将是 向下遍历到新的焦点遍历时首先接收焦点 循环植根于 aContainer。

默认实现返回循环中的第一个组件,自定义实现可能会寻找自定义指标,f.i。客户财产。简单的用法会将该策略设置为在其 contentPane 中有标记的框架,例如:

// 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 对管理器的默认值有自己的想法,实际上在创建第一个帧时无条件配置它(这会覆盖我们自己的默认值)

出路是创建一个dummy frame,然后设置策略:

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

【讨论】:

    最近更新 更多