如何在 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: 接下来,我删除了类级别的 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 打断了还是我遗漏了什么?

解决方法

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

使用 FocusAdapter:

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

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