获得焦点时如何选择 JFormattedTextField 中的所有文本?

Posted

技术标签:

【中文标题】获得焦点时如何选择 JFormattedTextField 中的所有文本?【英文标题】:How to select all text in a JFormattedTextField when it gets focus? 【发布时间】:2010-11-13 18:43:19 【问题描述】:

我有一个使用 Swing 的小型 Java 桌面应用程序。有一个数据输入对话框,其中包含一些不同类型的输入字段(JTextField、JComboBox、JSpinner、JFormattedTextField)。当我通过切换表单或用鼠标单击它来激活 JFormattedTextFields 时,我希望它选择它当前包含的所有文本。这样,用户就可以开始输入并覆盖默认值。

我该怎么做?我确实使用了在 JFormattedTextField 上调用 selectAll() 的 FocusListener/FocusAdapter,但它没有选择任何内容,尽管调用了 FocusAdapter 的 focusGained() 方法(请参见下面的代码示例)。

private javax.swing.JFormattedTextField pricePerLiter;
// ...
pricePerLiter.setFormatterFactory(
    new JFormattedTextField.AbstractFormatterFactory() 
    private NumberFormatter formatter = null;
    public JFormattedTextField.AbstractFormatter 
        getFormatter(JFormattedTextField jft) 
        if (formatter == null) 
            formatter = new NumberFormatter(new DecimalFormat("#0.000"));
            formatter.setValueClass(Double.class);
        
        return formatter;
    
);
// ...
pricePerLiter.addFocusListener(new java.awt.event.FocusAdapter() 
    public void focusGained(java.awt.event.FocusEvent evt) 
        pricePerLiter.selectAll();
    
);

有什么想法吗?有趣的是,选择其所有文本显然是 JTextField 和 JSpinner 的默认行为,至少在表单中切换时是这样。

【问题讨论】:

【参考方案1】:

我知道这有点老了,但我想出了一个更干净的解决方案,没有 invokeLater:

private class SelectAllOfFocus extends FocusAdapter 

    @Override
    public void focusGained(FocusEvent e) 
        if (! e.isTemporary()) 
            JFormattedTextField textField = (JFormattedTextField)e.getComponent();
            // This is needed to put the text field in edited mode, so that its processFocusEvent doesn't
            // do anything. Otherwise, it calls setValue, and the selection is lost.
            textField.setText(textField.getText());
            textField.selectAll();
        
    


【讨论】:

我不喜欢这段代码,因为它修改了组件内部状态,只是为了获得选择?【参考方案2】:

使用 SwingUtilities.invokeLater 封装您的调用,以便在处理完所有待处理的 AWT 事件后进行调用:

pricePerLiter.addFocusListener(new java.awt.event.FocusAdapter() 
    public void focusGained(java.awt.event.FocusEvent evt) 
        SwingUtilities.invokeLater(new Runnable() 
            @Override
            public void run() 
                pricePerLiter.selectAll();
            
        );
    
);

【讨论】:

谢谢,就是这样。我只能猜测 NumberFormatter 正在做一些撤消 selectAll() 的事情? +1 需要这个,无法立即记住我自己如何做到这一点,谷歌搜索并立即找到了这个答案。谢谢! 当你已经在 EDT 线程上时,为什么还要使用 invokeLater 来执行它? 因为invokeLater 确保所有待处理的 AWT 事件都已处理【参考方案3】:

camickr 的代码可以稍微改进一下。当焦点从 JTextField 传递到另一种组件(例如按钮)时,最后的自动选择不会被清除。可以这样修复:

    KeyboardFocusManager.getCurrentKeyboardFocusManager()
        .addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener()
    
        @Override
        public void propertyChange(final PropertyChangeEvent e)
        

            if (e.getOldValue() instanceof JTextField)
            
                    SwingUtilities.invokeLater(new Runnable()
                    
                            @Override
                            public void run()
                            
                                    JTextField oldTextField = (JTextField)e.getOldValue();
                                    oldTextField.setSelectionStart(0);
                                    oldTextField.setSelectionEnd(0);
                            
                    );

            

            if (e.getNewValue() instanceof JTextField)
            
                    SwingUtilities.invokeLater(new Runnable()
                    
                            @Override
                            public void run()
                            
                                    JTextField textField = (JTextField)e.getNewValue();
                                    textField.selectAll();
                            
                    );

            
        
    );

【讨论】:

【参考方案4】:

除了上述之外,如果您希望所有文本字段都使用此功能,您可以这样做:

KeyboardFocusManager.getCurrentKeyboardFocusManager()
    .addPropertyChangeListener("permanentFocusOwner", new PropertyChangeListener()

    public void propertyChange(final PropertyChangeEvent e)
    
        if (e.getNewValue() instanceof JTextField)
        
            SwingUtilities.invokeLater(new Runnable()
            
                public void run()
                
                    JTextField textField = (JTextField)e.getNewValue();
                    textField.selectAll();
                
            );

        
    
);

【讨论】:

【参考方案5】:

那是因为 JFormattedTextfield 会覆盖 processFocusEvent 以格式化获得焦点/失去焦点。

一个确定的方法是扩展 JFormattedTextField 并覆盖 processFocusEvent 方法:

new JFormattedTextField("...")   
        protected void processFocusEvent(FocusEvent e)   
            super.processFocusEvent(e);  
            if (e.isTemporary())  
                return;  
            SwingUtilities.invokeLater(new Runnable()   
                @Override  
                public void run()   
                    selectAll();  
                   
            );  
          
    ;

使用 focusListener 可能并不总是有效..因为它取决于相对于 processFocusEvent 调用它的时间。

【讨论】:

以上是关于获得焦点时如何选择 JFormattedTextField 中的所有文本?的主要内容,如果未能解决你的问题,请参考以下文章

获得焦点时选择“只读”<input /> 中的所有文本

如何打开 NSWindow 并选择窗口并获得焦点?

jQuery 屏蔽输入插件。当文本框获得焦点时选择所有内容

如何在我的 HTML 自定义元素中接收焦点和选择事件

Winform中Treeview控件失去焦点,如何将选择的节点还设置为高亮显示?

如何在没有焦点的情况下突出显示/选择 wpf 文本框中的文本?