Java 8 - Losing all keyboard input or focus after switching windows

Viewed 805

I'm running an application with similar behaviour to that in the test case below.

The problem is that when you switch focus to a different window by clicking on it and keeping the below application frame in view and then click directly into the text field with the focusGained listener, close the dialog and then all key input will be lost to the all of the text fields in the application.

If you click anywhere in the application first or the icon in the task bar to gain focus back then this does not occur.

This is Java 8 specific - in Java 7 it will not lose focus, not sure about java 9 but that is not an option anyway

The test case below demonstrates this behaviour.

public class FocusTest extends JFrame
{
    JTextField noFocus;

    public static void main(String[] args)
    {
         FocusTest ft = new FocusTest();
         ft.setVisible(true);
    }

    public FocusTest()
    {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setBounds(100,100,300,150);
        setLayout(new GridLayout(3,1, 2, 2));
        setTitle("Losing keyboard...");
        noFocus = new JTextField();
        add(noFocus);

        JTextField jft = new JTextField();
        jft.addFocusListener(new FocusAdapter()
        {
            @Override
            public void focusGained(FocusEvent e)
            {
                createDialog().setVisible(true);
                noFocus.requestFocusInWindow();
            }
        });
        add(jft);

        JButton jb = new JButton("OPEN");
        jb.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if(e.getActionCommand().equals("OPEN"))
                    createDialog().setVisible(true);
            }
        });
        add(jb);
    }

    private JDialog createDialog()
    {
        final JDialog jd = new JDialog(this, true);
        jd.setLocationRelativeTo(this);
        jd.setLayout(new BorderLayout());
        jd.getContentPane().add(new JTextField(), BorderLayout.CENTER);
        JButton jb = new JButton("Close");
        jb.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if(e.getActionCommand().equals("Close"))
                    jd.dispose();
            }
        });
        jd.getContentPane().add(jb, BorderLayout.SOUTH);
        jd.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        jd.pack();
        return jd;
    }
}
1 Answers

Not exactly sure what's happening, but one solution is to use a SwingUtilities.invokeLater():

@Override
public void focusGained(FocusEvent e)
{
    noFocus.requestFocusInWindow();

    SwingUtilities.invokeLater(new Runnable()
    {
        public void run()
        {
                createDialog().setVisible(true);
        }
    });
}

This will allow the text field to get focus properly before the dialog is made visible.

Related