Search code examples
javaswingfocusmouseeventjtextfield

How to send focus lost event before mouse pressed event?


I have a simple GUI with two components: a JTextField, and a custom component (MyComponent). Initially the text field has focus, and clicking on the custom component causes that to have focus.

Currently I am manually setting the focus using requestFocusInWindow, but the focusLost event happens after the mousePressed event has finished. Is there any way to get the focusLost event to happen before the mousePressed event finishes?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class Example  {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Example");
        frame.setLayout(new FlowLayout());
        JTextField textField = new JTextField(10);
        textField.addFocusListener(new FocusAdapter() {
            public void focusLost(FocusEvent event) {
                System.out.println("focusLost");
            }
        });
        frame.add(textField);
        frame.add(new MyComponent());
        frame.pack();
        frame.setVisible(true);
    }

    private static class MyComponent extends JComponent {
        public MyComponent() {
            setFocusable(true);
            addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent event) {
                    requestFocusInWindow();
                    System.out.println("mousePressed");
                }
            });
        }

        public Dimension getPreferredSize() {
            return new Dimension(400, 300);
        }
    }
}

Solution

  • It also needs to be validated (and stored)

    You can use an InputVerifier on the JTextField. It will validate the text in the text field before focus is transferred. If the data is not valid focus will stay on the text field.

    Edit:

    Can I remove this behaviour and instead revert the text field to the previous value if the data is not valid when losing focus?

    Instead of using a JTextField use a JFormattedTextField it will revert the data to the previous value. You don't need to use an InputVerifier. Read the section from the Swing tutorial on How to Use Formatted Text Fields for more information and examples.