7

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

示例:您有使用零值初始化的自旋控制。您选择它并键入“1”控件中的值现在是 1。

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

使用 Swing JSpinner,当您切换到旋转控件时,克拉位于左侧。您键入“1”,控件中的值现在是 10。

这让我(和我的用户)陷入困境,我想改变它。更重要的是,我想全局更改它,以便新行为适用于 JTextField、JPasswordField、JFormattedTextField、JTextArea、JComboBox、JSpinner 等。我发现这样做的唯一方法是将 FocusAdapter 添加到每个控件并覆盖 focusGained() 方法来做正确的事情[tm]。

必须有一种更简单、更不脆弱的方法。请?

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

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

4

5 回答 5

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 代码中处理焦点侦听器——这一切都将在更高级别上得到处理。

于 2008-09-15T20:32:04.607 回答
2

我自己还没有尝试过(不久前才涉足它),但您可能可以通过使用以下方法获取当前的焦点组件:KeyboardFocusManager(有一个静态方法 getCurrentKeyboardFocusManager())并向其添加 PropertyChangeListener。从那里,您可以确定该组件是否为 JTextComponent 并选择所有文本。

于 2008-09-15T21:53:12.743 回答
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 和所有其他文本编辑组件。这也允许该类将全选添加到可编辑的组合框和 JSpinners,您对文本编辑器组件的控制可能会受到更多限制。可以添加方便的方法:

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

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

于 2008-09-16T18:09:17.437 回答
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);
            }
        }
    }
}

有用!

于 2008-09-17T18:30:40.780 回答
0

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

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

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

于 2008-09-15T20:23:27.123 回答