Frage

I run into a problem using form default button when it (form) includes JFormattedTextField. On a form with such a field, if it happens to have focus (and was changed), you have to press OK twice to get your default button 'pressed'. I think I know why it happens - it's because first Enter gets consumed in Commit processing.

I was also able to make a workaround - if you change Formatter to commit on each valid edit, then you will get proper behavior, but this a) forces you to specify formatters explicilty, and b) it's not possible to revert to 'old' value (eg. using Escape, or programatically).

Code below demonstrates that: when you run it field at the top commits on each edit and works with single Enter (but you cannot revert), field at the bottom allows reverts, but needs two Enters if edited.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.Date;

import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.text.DateFormatter;

public class ExFrame extends JFrame {

    private JPanel contentPane;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ExFrame frame = new ExFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    /**
     * Create the frame.
     */
    public ExFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPane);

        JFormattedTextField ff_1, ff_2;

        //ff_1 has modified behavior of commit on each (valid) edit
        DateFormatter f=new DateFormatter();
        f.setCommitsOnValidEdit(true);

        ff_1 = new JFormattedTextField(f);
        ff_1.setValue(new Date());

        //ff_2 has default behavior 
        ff_2 = new JFormattedTextField(new Date());

        contentPane.add(ff_1, BorderLayout.NORTH);
        contentPane.add(ff_2, BorderLayout.SOUTH);

        JButton btnDefault = new JButton("I am default button");
        contentPane.add(btnDefault, BorderLayout.CENTER);
        getRootPane().setDefaultButton(btnDefault);
    }
}

So the question is: Is there a way to get JFormattedTextField both commit on Enter (so input is verified but only once) and if succesfully validated, activate default button (with single press)?

War es hilfreich?

Lösung

The basic trick is the fool the keyBinding mechanism into believing that the keyStroke wasn't handled by the textField. To achieve that, we need to subclass the JFormattedTextField and override its processKeyBindings to return false (meaning: "couldn't use").

Something like:

JFormattedTextField multiplex = new JFormattedTextField() {
    KeyStroke enter = KeyStroke.getKeyStroke("ENTER");
    @Override
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                                        int condition, boolean pressed) {
        boolean processed = super.processKeyBinding(ks, e, condition,
                                                    pressed);

        if (processed && condition != JComponent.WHEN_IN_FOCUSED_WINDOW
                && enter.equals(ks)) {
            // Returning false will allow further processing
            // of the bindings, eg our parent Containers will get a
            // crack at them and f.i. route to a default button.
            return !isEditValid();
        }
        return processed;
    }

};
multiplex.setValue(new Date());

Andere Tipps

for Date / Number instance is (in most cases) better use JSpinner rather than JFormattedTextField, then there you can only to set for DateSpinnerModel with Locale or SimpleDateFormat,

and for JSpinner with Number Instance (valid for JTextField) you have to add Document for removing/filtering for unwanted chars

Enter is commonly used to accept the currently value, and therefore enter in JFTF does this as well. you can disable it by doing:

ff_1.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), new Object());
ff_2.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), new Object());

bye and be Cool ;)

Neither of your answers solved my application problem. However, it seemed that the problem solution was much simpler in my case:

private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {
   add(jTextField1);          //this reacts after the "ENTER" gets pressed
   jButton1.doClick();        //this activates the button with Enter
   jTextField1.setText("");   //this removes the text from a text-field
  jTextField1.grabFocus();    //this sets a cursor within a text-field

//Whenever the Enter is pressed, after the typed text, the action is performed again.
    }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top