Name: rmT116609 Date: 05/20/2003
FULL PRODUCT VERSION :
java version "1.4.2-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-beta-b19)
Java HotSpot(TM) Client VM (build 1.4.2-beta-b19, mixed mode)
(Note this bug was also present in 1.4.1.)
FULL OS VERSION :
Microsoft Windows 2000 [Version 5.00.2195]
A DESCRIPTION OF THE PROBLEM :
Applet contains a JPanel that has several child components, one of which has the focus. Removal of that JPanel (from the JApplet) causes a FOCUS_GAINED event for another child component of that JPanel (the same JPanel which is being removed). Focus remains on that removed component.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Run the applet
2.Mouse-click the first button
3.Watch the Java console output
4.Notice that second button gets the focus (and keeps it) after it has been removed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the focus to be either:
1. Lost to all components of the applet
or
2. Gained by some Applet component that is still displayable.
ACTUAL -
Java console shows that after the panel is removed, the second button of that panel (which is no longer displayable) gets a FOCUS_GAINED event. The focus stays there (as long as you don't click away from the applet, e.g. to activate the console window).
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Console output after clicking first button:
removing old panel
adding new panel
FOCUS_LOST by 1
FOCUS_GAINED by 2
(Note if you see a final "FOCUS_LOST by 2", it is because you clicked away from the applet -- don't do that.)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
// JApplet1.java
// Demonstrates FOCUS_GAINED bug.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JApplet1 extends JApplet implements FocusListener, ActionListener
{
private int nextBtnNum = 1;
private JPanel curPanel;
private JButton curBtns[];
public void init()
{
getContentPane().setLayout(new BorderLayout(0,0));
setSize(400,100);
createCurPanel();
getContentPane().add(BorderLayout.CENTER, curPanel);
curBtns[0].requestFocus();
}
// Create a 3-button panel into the "curPanel" variable.
private void createCurPanel()
{
curPanel = new JPanel();
curPanel.setFocusCycleRoot(true);
curPanel.setFocusTraversalPolicy(new ContainerOrderFocusTraversalPolicy());
curPanel.addFocusListener(this);
curBtns = new JButton[3];
curPanel.setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
for (int m=0; m < 3; m++) {
JButton btn = new JButton(String.valueOf(nextBtnNum++));
curPanel.add(btn);
btn.addActionListener(this);
btn.addFocusListener(this);
curBtns[m] = btn;
}
}
// Replace curPanel by a new 3-button panel
private void replacePanel()
{
System.out.println("removing old panel");
getContentPane().remove(curPanel);
createCurPanel();
System.out.println("adding new panel");
getContentPane().add(BorderLayout.CENTER, curPanel);
validate();
// If we don't do a requestFocus here, the focus will be left
// on one of the buttons of the panel that was removed.
// If we want the focus to go to the new panel, we have to do
// the following:
//SwingUtilities.invokeLater(
// new Runnable() { public void run() { curBtns[0].requestFocus(); }});
// Simply calling
// curBtns[0].requestFocus();
// here doesn't work. Is this another bug?
}
private String describeComponent(Component c)
{
if (c instanceof JButton) return ((JButton)c).getText();
if (c == curPanel) return "curPanel";
return c.toString();
}
public void focusGained(FocusEvent e)
{
System.out.println("FOCUS_GAINED by " + describeComponent(e.getComponent()));
}
public void focusLost(FocusEvent e)
{
System.out.println("FOCUS_LOST by " + describeComponent(e.getComponent()));
}
// Get button clicks
public void actionPerformed(ActionEvent e)
{
replacePanel();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I made my own FocusTraversalPolicy that returns null from getComponentAfter for a component that I know I am about to remove. This involves marking every component that I am about to remove. This workaround is only a stopgap and we are anxiously awaiting a bug fix.
(Review ID: 185858)
======================================================================