Yes, there is a simpler way...
Why populating the actionmap of a custom editor and not just editing the actionmap of the DefaultEditor
?
Let's supply the DefaultEditor
's JFormattedTextField
with a custom action for the input notify event:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.text.TextAction;
public class OnEnterSpinner extends JPanel {
private final JSpinner spin;
private final JSpinner.DefaultEditor editor;
private final JFormattedTextField field;
private final class OnEnterAction extends TextAction {
private OnEnterAction() {
super(JTextField.notifyAction); //The name of the TextAction. Let's say it is its key.
}
@Override
public void actionPerformed(final ActionEvent actevt) {
if (getFocusedComponent() == field)
System.out.println("The user pressed ENTER for: \"" + field.getText() + "\".");
}
}
private OnEnterSpinner() {
spin = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1)); //Your values here. Let's say for now this is a spinner for integers.
spin.setPreferredSize(new Dimension(100, 20));
//We need a DefaultEditor (to be able to obtain the JFormattedTextField and customize it).
editor = new JSpinner.DefaultEditor(spin);
field = editor.getTextField();
field.setEditable(true); //Allow user input (obvious reasons).
//And here, you register the custom action!
field.getActionMap().put(JTextField.notifyAction, new OnEnterAction()); //I found the proper key for the map: "notifyAction".
spin.setEditor(editor);
add(spin);
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("OnEnterSpinner demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new OnEnterSpinner());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
If, furthermore, you need to check the validity of the entered value via a custom AbstractFormatter
which you supplied to the JFormattedTextField
, then just call JSpinner#commitEdit()
upon ENTER:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.text.ParseException;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.text.TextAction;
public class CommitOnEnterSpinner extends JPanel {
private final JSpinner spin;
private final JSpinner.DefaultEditor editor;
private final JFormattedTextField field;
private final class OnEnterAction extends TextAction {
private OnEnterAction() {
super(JTextField.notifyAction);
}
@Override
public void actionPerformed(final ActionEvent actevt) {
if (getFocusedComponent() == field) { //This check may be redundant in this case.
System.out.println("The user pressed ENTER for: \"" + field.getText() + "\".");
try {
//Commit the edits, upon carriage return:
spin.commitEdit();
//If successfull, then handle it as desired:
JOptionPane.showMessageDialog(null, "Yes! This is a valid value.", "OK", JOptionPane.PLAIN_MESSAGE);
}
catch (final ParseException pe) {
//If failed, then handle the unaccepted value:
JOptionPane.showMessageDialog(null, "Sorry, \"" + field.getText() + "\" is not a valid value.", "Oups!", JOptionPane.INFORMATION_MESSAGE);
}
}
}
}
private CommitOnEnterSpinner() {
spin = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1)); //Your values here. Let's say for now this is a spinner for integers.
spin.setPreferredSize(new Dimension(100, 20));
//We need a DefaultEditor (to be able to obtain the JFormattedTextField and customize it).
editor = new JSpinner.DefaultEditor(spin);
field = editor.getTextField();
field.setEditable(true); //Allow user input (obvious reasons).
//And here, you register the custom action!
field.getActionMap().put(JTextField.notifyAction, new OnEnterAction());
spin.setEditor(editor);
add(spin);
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("CommitOnEnterSpinner demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CommitOnEnterSpinner());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}