代码之家  ›  专栏  ›  技术社区  ›  Dale Wilson

当Java/Swing控件获得焦点时,是否有一种简单的方法来更改其行为?

  •  7
  • Dale Wilson  · 技术社区  · 16 年前

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

    示例:您有一个自旋控件,该控件的初始化值为零。您可以使用tab键单击它并键入“1”。控件中的值现在为1。

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

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

    这让我(和我的用户)陷入困境,我想改变它。更重要的是,我想对其进行全局更改,使新行为适用于JTextField、JPasswordField、JFormattedTextField、JTextArea、JComboBox、JSpinner等。我找到的唯一方法是在每个控件中添加一个FocusAdapter,并重写focusGoverd()方法来做正确的事情[tm]。

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

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

    5 回复  |  直到 16 年前
        1
  •  2
  •   rcreswick    16 年前

    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是我发现的最常用的方法。

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

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

        2
  •  2
  •   Avrom    16 年前

    我自己也没有尝试过(只是在不久前才涉猎过),但您可能可以使用以下方法获得当前的焦点组件: 向其添加PropertyChangeListener的过程。 从那里,您可以确定该组件是否为JTextComponent,并选择all text。

        3
  •  2
  •   shemnon    16 年前

    可以编写将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和所有其他文本编辑组件中。这还允许类将全选添加到可编辑的组合框和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);
      }
    }
    

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

        4
  •  1
  •   Dale Wilson    16 年前

    在阅读到目前为止的回复后(谢谢!),我将最外层的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);
                }
            }
        }
    }
    

    它起作用了!

        5
  •  0
  •   Alexandre Brasil    16 年前

    addFocusListener(监听器)

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

    有很多AOP框架可供选择。我喜欢 JBossAOP AspectJ