首页 > 解决方案 > 如何在 Java 中使用 Swing JSpinner 的焦点事件?

问题描述

我正在使用 NetBeans 创建一个桌面 Java 应用程序(只是为了好玩和扩展知识)。我在面板中有一个微调器(和一个按钮),我需要检测微调器何时失去焦点。我已经尝试了几件事,但没有任何东西会为 Spinner 触发 focusGained 或 focusLost。我怎样才能让它工作?

我试过的:

尝试 1:我尝试在类级别使用“实现 FocusListener”,然后按如下方式覆盖 focusGained 和 focusLost 事件。

    @Override
    public void focusGained(FocusEvent e) {
        String name = e.getComponent().getClass().getName();
        System.out.println("Focus gained : " + name);
    }

    @Override
    public void focusLost(FocusEvent e) {
        String name = e.getComponent().getClass().getName();
        System.out.println("Focus lost : " + name);
    }

我添加了如下监听器。起初我只有注释掉的行。这对按钮非常有效,但是 Spinner 在单击它、更改它然后单击按钮时从未触发任何事件。因此,我尝试注释掉该行并添加下面的行以尝试使用底层的 TextField。这又没有用。

        jButton1.addFocusListener(this);
        //jSpinner1.addFocusListener(this);
((JSpinner.DefaultEditor)jSpinner1.getEditor()).getTextField().addFocusListener(this);   

尝试 2:接下来我删除了 Class 级别的 FocusListener 并尝试构建一个新的内联对象,如下所示。我再次尝试直接在 Spinner 上构建它,当它不起作用时,我尝试在底层 TextField 上构建它。同样,这两个事件都没有被触发。

    //jSpinner1.addFocusListener(new FocusListener() {
    ((JSpinner.DefaultEditor)jSpinner1.getEditor()).getTextField().addFocusListener(new FocusListener() {
      @Override
      public void focusGained(FocusEvent e) {
        String name = e.getComponent().getClass().getName();          
        System.out.println("Focus gained : " + name);
      };
      @Override
      public void focusLost(FocusEvent e) {
        String name = e.getComponent().getClass().getName();          
        System.out.println("Focus lost : " + name);
      };
      });

尝试 3:最后我尝试构建一个单独的 focusAdapter,如下所示。我再次尝试先将其直接附加到 Spinner,然后再附加到底层的 TextField 并且再次没有触发任何事件。

        FocusAdapter focusAdapter = new FocusAdapter()
        {
            public void focusGained(FocusEvent e)
            {
                String name = e.getComponent().getClass().getName();          
                System.out.println("Focus gained : " + name);
            }
            
            public void focusLost(FocusEvent e) {
                String name = e.getComponent().getClass().getName();          
                System.out.println("Focus lost : " + name);
            };            
        };        
        
        //jSpinner1.addFocusListener(focusAdapter);
        ((JSpinner.DefaultEditor)jSpinner1.getEditor()).getTextField().addFocusListener(focusAdapter);

我要补充一点,我已经尝试使用 AdoptOpenJDK jdk-11.0.11.9-hotspot 和 Oracle OpenJDK jdk-16.0.1,看看这是否会有所不同。两者的结果相同。

我还应该补充一点,我已确保 Spinner 的“focusable”属性和“requestFocusEnabled”属性都设置为“true”。

我完全不知所措。所有 3 种方法都应该适用于其他非 Spinner 组件。Spinners 只是打破了焦点还是我错过了什么?

标签: javaswingjspinner

解决方案


感谢@MadProgrammer 的提示,我得到了答案。我在设置监听器的地方有 DateEditor 和 setEditor 行。这清除了我刚刚设置的监听器。我将这两行移到了设置侦听器之前,现在以下两组代码都适用于我。

使用焦点适配器:

        JSpinner.DateEditor de = new JSpinner.DateEditor(jSpinner1, "h:mm:ss a");
        jSpinner1.setEditor(de);        
        
        FocusAdapter focusAdapter = new FocusAdapter()
        {
            public void focusGained(final FocusEvent e)
            {
                String name = e.getComponent().getClass().getName();          
                System.out.println("Focus gained : " + name);
            }
            
            public void focusLost(final FocusEvent e) {
                String name = e.getComponent().getClass().getName();          
                System.out.println("Focus lost : " + name);
            };            
        };        
        
        ((JSpinner.DefaultEditor)jSpinner1.getEditor()).getTextField().addFocusListener(focusAdapter);   

使用内联监听器:

    ((JSpinner.DefaultEditor)jSpinner1.getEditor()).getTextField().addFocusListener(new FocusListener() {
      @Override
      public void focusGained(FocusEvent e) {
        String name = e.getComponent().getClass().getName();          
        System.out.println("Focus gained : " + name);
      };
      @Override
      public void focusLost(FocusEvent e) {
        String name = e.getComponent().getClass().getName();          
        System.out.println("Focus lost : " + name);
      };
      });

我怀疑但没有尝试过,如果我在附加监听器之前也将这两行移到了我尝试的第一种方法(在我上面的原始问题中)也可以工作。


推荐阅读