-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
None
-
1.3.0
-
generic
-
generic
Name: skT45625 Date: 05/09/2000
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)
In 1.3 the code for BasicMenuItemUI was changed to
add an additional check that breaks restoring focus to components
residing in internal frames. Specifically, in the ChangeHandler inner
class there is method called validateKeyboardActions which is called
before a JMenu is posted and after it is unposted. The code keeps track
of which component had the focus before the menu is posted and will
attempt to restore the focus to that component after the menu is
unposted.
Here's the problem. In 1.3 a check was added that ignores components
that don't share the same rootpane as the menu being posted. If the
application is set up so the menubar is parented by a toplevel JFrame
and the internal frames are parented by a JDesktopPane(which resides in
the JFrame's contentPane), then this check will always fail! Here's the
offending code fragment from the validateKeyboardActions method:
if ((wasFocused instanceof JComponent) &&
((JComponent)wasFocused).getRootPane() != menu.getRootPane()) {
wasFocused = null;
}
The "wasFocused" variable contains the component that had the focus
before the JMenu was posted.
Here's a testcase that clearly shows the bug. Just access the "Test" menu and
you'll see that the focus is not restored to the component in the internal
frame that had it before the menu got posted.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class foo extends JFrame {
public static void main(String[] args) {
new foo();
}
public foo() {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}}
);
JDesktopPane dtp = new JDesktopPane();
setContentPane(dtp);
final JInternalFrame jif = new JInternalFrame("Test",true,true,true,true);
jif.setOpaque(true);
jif.setBackground(Color.gray);
jif.getContentPane().setLayout(new FlowLayout());
jif.setBounds(0,50,600,200);
jif.setVisible(true);
dtp.add(jif);
// HACK ALERT - use timer to get initial frame selected
Timer t = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
jif.setSelected(true);
} catch (Exception x) {}
}
});
t.setRepeats(false);
t.start();
JButton b = new JButton("JButton");
JTextField tf = new JTextField(10);
jif.getContentPane().add(b);
jif.getContentPane().add(tf);
jif.pack();
FocusHandler fh = new FocusHandler();
b.addFocusListener(fh);
tf.addFocusListener(fh);
JMenuBar mb = new JMenuBar();
setJMenuBar(mb);
JMenu menu = new JMenu("Test");
JMenuItem mi = new JMenuItem("Dummy Item");
menu.add(mi);
mb.add(menu);
pack();
setBounds(300,300,400,200);
setVisible(true);
}
private class FocusHandler implements FocusListener {
public void focusLost(FocusEvent e) {
System.out.println("FOCUS LOST, SRC="+e.getSource().getClass().getName
());
}
public void focusGained(FocusEvent e) {
System.out.println("FOCUS GAINED, SRC="+e.getSource().getClass
().getName());
}
}
}
(Review ID: 104620)
======================================================================