JDK-6212464 : Undesired JOptionPane loop in FocusLost event
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.2,6
  • Priority: P4
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2004-12-24
  • Updated: 2011-01-19
  • Resolved: 2009-06-18
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Windows XP Home SP2

A DESCRIPTION OF THE PROBLEM :
In the code sample below the JOptionPane pops up 4 times before one can enter the Textfield again after an erroneous input.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
JOptionPane should appear only once.
ACTUAL -
Clicking [OK] made the OptionPane reappear.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 
public class T extends JFrame
{
  JTextField tf1;
 
  public T()
  { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container cp= getContentPane();
    cp.setLayout(null);
    setSize(500,300);
    tf1= new JTextField();
    tf1.setBounds(200,80,100,25);
    tf1.addFocusListener(new FocusAdapter()
    { public void focusLost(FocusEvent e)
      { try
        { double d= Double.parseDouble(tf1.getText());
          if (d<4. || d>50.)
          { throw new NumberFormatException();
          }
        }
        catch (NumberFormatException nfe)
        { JOptionPane.showMessageDialog(T.this,
           "Erroneous input.\nValid range is 4-50.",
          "Error", JOptionPane.ERROR_MESSAGE);
          tf1.requestFocus();
        }
      }
    });
    cp.add(tf1);
    JTextField tf2= new JTextField();
    tf2.setBounds(200,120,100,25);
    cp.add(tf2);
    setVisible(true);
  }
 
  static public void main(String args[])
  { new T();
  }
}

---------- END SOURCE ----------
###@###.### 2004-12-24 10:11:24 GMT

Comments
EVALUATION The fix for 6806217 "implement synthetic focus model for MS Windows" eliminates the problem. A decision on which component to focus is taken on the Java side, native focus messages no longer interfere in the process.
18-06-2009

EVALUATION There are two duplicates of this bug: 6462093 - FocusEvent processed twice when requestFocus after JOptionPane.showMessage() 6555704 - Extra focus gain & focus lost event is triggered in win xp. here is most useful part of their evaluation: I think I knwo the cause of the problem: the test requests focus on tezt field just after closing dialog. This request is processsed by our focus subsystem and finally delivered to KFM.shouldNativelyFocusHeavyweight(). At this point native focus owner is null, native focused window is the frame, and there are no pending focus requests. In this case we thinks that we should natively set focus and so this produces problematic focus events. Imho in this case we should do nothing and wait when DKFM will process WINDOW_GAINED_FOCUS on the frame and request focus for text field as a most recent focus owner (note: most recent focus owner has been already updated in requestFocus()). The only question is if it is possible to have similar situation (naive focuse owner == null and native focused window != null) not during the activation process. (need to think about this) *** (#4 of 5): 2007-05-14 20:30:34 MSD ###@###.### Well, it looks like we can not filter out the request in shouldNativelyFocusHeavyweight() because the situation is the same as for request we do in DKFM on WINDOW_GAINED_FOCUS (or we need to add one more majic flag for this). Another approach would be to not request focus in DKFM is there are pending requests, but this way we will not restore focus to the compoment which temporary lost focus (so this will looks trange, though there is no such statements in the Focus spec). So, both approaches have some disadvantages and the problem is not a spec violation thus I'm postponing the fix for now (hope will find a better way to fix or more reasons to fix it :) *** (#5 of 5): 2007-05-15 12:41:38 MSD ###@###.###
15-05-2007

EVALUATION The problem is the following. When user clicks on tf2 two focus message are triggered. 1st - FocusLost on tf1, 2nd - FocusGained on tf2. When the first FocusLost event is handled by the listener it shows OptionPane and then requests focus back to tf1. After tf1 loses focus tf2 gets it before the OptionPane is shown. So, when the OptionPane is displayed, the last focus owner of the frame is tf2. When user closes the OptionPane focus turns to tf1 as it was requested, but then DKFM tries to set it on tf2 as it was the last focus owner. Thus tf1 again loses focus. This all goes asynchroniously and the bug appears due to thread race. Plase see Work Around. ###@###.### 2005-06-17 12:19:26 GMT
17-06-2005

WORK AROUND Request focus in the listener through EventDispatch thread, like the following: EventQueue.invokeLater(new Runnable() { public void run() { tf1.requestFocus(); } }); This will allow to avoid the thread race. ###@###.### 2005-06-17 12:19:26 GMT
17-06-2005