小さな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の両方のデフォルトの動作であることです。
呼び出しを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();
}
});
}
});
上記に加えて、すべてのテキストフィールドにこれが必要な場合は、次のようにすることができます:
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();
}
});
}
}
});
私はこれが少し古いことを知っていますが、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();
}
}
}
これは、JFormattedTextfieldがprocessFocusEventをオーバーライドして、フォーカス獲得/フォーカス喪失でフォーマットするためです。
確実な方法の1つは、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に関連して呼び出される時間に依存するためです。
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();
}
});
}
}
});