FULL PRODUCT VERSION :
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) Client VM (build 24.45-b08, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
When programmatically selecting frames, it is possible to end up with the focused component in a different frame than the frame that is selected. This is because focus is done asynchronously, so the permanent focus owner is not yet accurate when JInternalFrame.restoreSubcomponentFocus is called.
Even though we don't leave selection on interim frame, we need all the events to be fired in order to react on them and stay event driven. Both frames are visible to the user, and images, words, etc. change because of those events. We cannot simply reject the first selection move because 1) we need all the events fired and 2) the frames are in non-coupled, independent code.
The fix in JInternalFrame for bug number 6505027 introduced this bug. The internal comments in JInternalFrame setSelected and restoreSubcomponentFocus also somewhat address this need.
REGRESSION. Last worked in version 6u43
ADDITIONAL REGRESSION INFORMATION:
java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b06)
Java HotSpot(TM) Client VM (build 17.0-b16, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create and show a JDesktopPane in a JFrame.
Create and add two JInternalFrames, each containing at least one focusable component, to the desktop pane.
After add, the second frame should be selected and have focus.
Programmatically select the first frame and then the second frame.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The second frame is selected and its child component is the focused component.
ACTUAL -
The second frame is selected but the focused component is in the non-selected (first) frame.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.Container;
import java.awt.FlowLayout;
import java.beans.PropertyVetoException;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class JInternalFrameSelectionTest extends JFrame
{
public static void main(String args[])
{
JFrame mainFrame = new JInternalFrameSelectionTest();
mainFrame.setSize(700, 400);
mainFrame.setVisible(true);
JDesktopPane desktopPane = new JDesktopPane();
mainFrame.getContentPane().add(desktopPane);
final JInternalFrame frame1 = new JInternalFrame("Frame 1", true, true, true, true);
frame1.setBounds(10, 10, 300, 300);
Container contentPane = frame1.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(new JTextField("frame 1 field"));
desktopPane.add(frame1);
frame1.setVisible(true);
final JInternalFrame frame2 = new JInternalFrame("Frame 2", true, true, true, true);
frame2.setBounds(350, 10, 300, 300);
contentPane = frame2.getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(new JTextField("frame 2 field"));
desktopPane.add(frame2);
frame2.setVisible(true);
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
try
{
frame1.setSelected(true);
}
catch (PropertyVetoException e)
{
}
try
{
frame2.setSelected(true);
}
catch (PropertyVetoException e)
{
}
}
});
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Extend JInternalFrame and override restoreSubcomponentFocus to remove the check that the permanent focus owner is descending from the frame being selected. However, since lastFocusOwner and setLastFocusOwner are private, they had to be "hacked" via reflection.