Set caret position where the mouse clicked

31 Views Asked by At

I have several JSpinner with a SpinnerNumberModel. Whenever I click on a JSpinner, which hasn't yet the focus, it will focus the JSpinner, but the caret will always be set on the left-most position of the number.

I need to wait a moment and click a second time to get the caret set on the location I want to set it. If I click too fast, it will select the whole number.

What do I need to do so that the caret will be positioned at the mouse location with the first click, even when the JSpinner doesn't have the focus?

1

There are 1 best solutions below

0
MadMike On

To achieve that, you need to add a MouseListener which translates the mouse-position to the caret-position and sets the caret as described in this question: https://stackoverflow.com/a/2202041/406423

public class GUITestJSpinner extends JPanel {
    private JSpinner integerSpinner;
    private JSpinner doubleSpinner;
    private JSpinner dateSpinner;
    ...

    public GUITestJSpinner() {
        ...

        integerSpinner.setModel(new SpinnerNumberModel(100, null, null, 10));
        addEditorMouseListener(integerSpinner);

        doubleSpinner.setModel(new SpinnerNumberModel(100.23, null, null, 10.0));
        addEditorMouseListener(doubleSpinner);

        dateSpinner.setModel(new SpinnerDateModel(Calendar.getInstance().getTime(), null, null, Calendar.DAY_OF_YEAR));
        addEditorMouseListener(dateSpinner);
    }

    private static void addEditorMouseListener(JSpinner jspinner) {
        JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor) jspinner.getEditor();
        editor.getTextField().addMouseListener(
            new MouseAdapter() {
                public void mousePressed(final MouseEvent e) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            JTextField tf = (JTextField) e.getSource();
                            int offset = tf.viewToModel(e.getPoint());
                            tf.setCaretPosition(offset);
                        }
                    });
                }
            }
        );
    }

Note that setting model to new model will reset that behavior. You either need to add the MouseListener again or change the values of the model in-place like this:

...
        SpinnerNumberModel snm = (SpinnerNumberModel) doubleSpinner.getModel();
        snm.setValue(220.34);
        snm.setStepSize(20.0);
...

Also note that even though this works as expected with the JSpinner using the SpinnerDateModel, it still behaves very 'strange' when clicking the up and down arrows. I suggest to refrain using JSpinner to select a date and use JXDatePicker from SwingX instead.

Last note: Double-clicking to select the content of the JSpinner doesn't work anymore. You will need to triple-click to select the content of the JSpinner.