获得焦点时如何选择 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 中的所有文本?的主要内容,如果未能解决你的问题,请参考以下文章