有没有一种简单的方法来改变Java / Swing控件获得焦点时的行为?

时间:2008-09-15 20:10:57

标签: java user-interface swing

对于我使用的大多数GUI,当包含文本的控件获得焦点时,将选择控件的全部内容。这意味着如果您刚刚开始输入,则完全替换以前的内容。

示例:您具有使用零值初始化的旋转控件。您选中它并键入“1”控件中的值现在为1.

使用Swing,这不会发生。未选择控件中的文本,克拉显示在现有文本的一端或另一端。继续上面的例子:

使用Swing JSpinner,当您选择旋转控件时,克拉位于左侧。键入“1”,控件中的值现在为10.

这让我,(和我的用户)走上了墙,我想改变它。更重要的是,我想全局更改它,因此新行为适用于JTextField,JPasswordField,JFormattedTextField,JTextArea,JComboBox,JSpinner等。我找到的唯一方法就是为每个控件添加一个FocusAdapter并覆盖focusGained()方法来做正确的事[tm]。

必须有一种更简单,更不易碎的方式。请?

编辑:此特定案例的另一条信息。我正在使用的表单是使用Idea的表单设计器生成的。这意味着我通常不会编写代码来创建组件。有可能告诉Idea你想自己创建它们,但这是我想避免的麻烦。

座右铭:所有优秀的程序员基本都是懒惰的。

5 个答案:

答案 0 :(得分:2)

当我过去需要这个时,我已经创建了我想要添加“自动清除”功能的组件的子类。例如:

public class AutoClearingTextField extends JTextField {
   final FocusListener AUTO_CLEARING_LISTENER = new FocusListener(){
      @Override
      public void focusLost(FocusEvent e) {
         //onFocusLost(e);
      }

      @Override
      public void focusGained(FocusEvent e) {
         selectAll();
      }
   };

   public AutoClearingTextField(String string) {
      super(string);
      addListener();
   }

   private void addListener() {
      addFocusListener(AUTO_CLEARING_LISTENER);      
   }
}

最大的问题是我没有找到一个“好”的方法来获得所有标准构造函数而不编写覆盖。添加它们,并强制调用addListener是我发现的最常用的方法。

另一种选择是在具有ContainerListeer的顶级容器上监视ContainerEvents以检测新窗口小部件的存在,并根据已添加的窗口小部件添加相应的焦点侦听器。 (例如:如果容器事件是由添加TextField引起的,则添加一个知道如何选择TextField中所有文本的焦点侦听器,依此类推。)如果添加了Container,则需要递归添加ContainerListener到那个新的子容器。

无论哪种方式,您都不需要在实际的UI代码中使用焦点侦听器 - 它将在更高级别处理。

答案 1 :(得分:2)

我自己没有尝试过这种方法(前一段时间只涉及它),但您可以使用以下方法获取当前关注的组件: KeyboardFocusManager(有一个静态方法getCurrentKeyboardFocusManager()) 向它添加一个PropertyChangeListener。 从那里,您可以找出组件是否是JTextComponent并选择所有文本。

答案 2 :(得分:2)

可以编写将FocusListener附加到所需文本字段的单独类。所有焦点监听器都会在获得焦点时调用文本小部件上的selectAll()。

public class SelectAllListener implements FocusListener {
  private static INSTANCE = new SelectAllListener();

  public void focusLost(FocusEvent e) { }

  public void focusGained(FocusEvent e) {
    if (e.getSource() instanceof JTextComponent) {  
      ((JTextComponent)e.getSource()).selectAll();
    }
  };

  public static void addSelectAllListener(JTextComponent tc) {
    tc.addFocusListener(INSTANCE);
  }

  public static void removeSelectAllListener(JTextComponent tc) {
    tc.removeFocusListener(INSTANCE);
  }
}

通过接受JTextComponent作为参数,可以将此行为直接添加到JTextArea,JPasswordField和所有其他文本编辑组件。这也允许类将select all添加到可编辑的组合框和JSpinner,其中您对文本编辑器组件的控制可能更有限。可以添加便利方法:

public static void addSelectAllListener(JSpinner spin) {
  if (spin.getEditor() instanceof JTextComponent) {
    addSelectAllListener((JTextComponent)spin.getEditor());
  }
}

public static void addSelectAllListener(JComboBox combo) {
  JComponent editor = combo.getEditor().getEditorComponent();
  if (editor instanceof JTextComponent) {
    addSelectAllListener((JTextComponent)editor);
  }
}

此外,删除侦听器方法可能不需要,因为侦听器不包含对任何其他实例的外部引用,但可以添加它们以使代码审查更顺畅。

答案 3 :(得分:1)

到目前为止阅读回复后(谢谢!)我将最外面的JPanel传递给以下方法:

void addTextFocusSelect(JComponent component){
    if(component instanceof JTextComponent){
        component.addFocusListener(new FocusAdapter() {
                @Override
                public void focusGained(FocusEvent event) {
                    super.focusGained(event);
                    JTextComponent component = (JTextComponent)event.getComponent();
                    // a trick I found on JavaRanch.com
                    // Without this, some components don't honor selectAll
                    component.setText(component.getText());
                    component.selectAll();
                }
            });

    }
    else
    {
        for(Component child: component.getComponents()){
            if(child instanceof JComponent){
                addTextFocusSelect((JComponent) child);
            }
        }
    }
}

有效!

答案 4 :(得分:0)

我知道的唯一方法是创建一个FocusListener并将其附加到您的组件。如果您希望此FocusListener对应用程序中的所有组件都是全局的,您可以考虑使用面向方面编程(AOP)。使用AOP可以对其进行一次编码并将焦点侦听器应用于应用程序中实例化的所有组件,而无需在整个应用程序中复制并粘贴 component.addFocusListener(侦听器)代码。

您的方面必须拦截JComponent(或您要将此行为添加到的子类)的创建,并将焦点侦听器添加到新创建的实例。 AOP方法比将FocusListener复制并粘贴到整个代码更好,因为您将它全部保存在单个代码中,并且一旦您决定更改全局行为(如删除侦听器),就不会创建维护噩梦JSpinners。

有许多AOP框架可供选择。我喜欢JBossAOP,因为它是100%纯Java,但你可能想看看AspectJ