Following program behaves differently on different platforms. JDK1.2.2 is
ok on (presumably) all platforms. The problem demonstrates itself only on
Linux (tested on RedHat6.2) and with Gnome window manager.
The program tries to insert menu items into already displayed popup menu. It
works fine with JDK1.2.2 and the problem is introduced in JDK1.3.
I am not 100% sure but it seems to me that the call to
GlobalCursorManager.updateCursorImmediately();
on line 737 in java.awt.Container
surprisingly moves the heavyweight popup container to the location 0,0
on the screen. Next call to pack() (and from there to the mentioned
updateCursorImmediately) moves the window back to the correct
location.
Any fix or workaround would be highly appreciated since our bug #7872
http://www.netbeans.org/bugs-cgi/show_bug.cgi?id=7872
depends on this.
package test;
import java.awt.*;
import javax.swing.*;
public class MenuTest extends JFrame
implements java.awt.event.ActionListener {
private static JButton b1;
private static JButton b2;
/** Creates new MenuTest */
public MenuTest() {
super ("Test of menu");
}
/** Shows the menu.
* @param hack use hack or not?
*/
private void showMenu (final boolean hack) {
Dimension d = getSize ();
d.width /= 2;
d.height /= 2;
final JPopupMenu menu = new JPopupMenu ();
final Component popupParent = getContentPane();
menu.show(popupParent, d.width, d.height);
for (int i = 0; i < 19; i++) {
final String name = "Item " + i;
try {
SwingUtilities.invokeLater(new Runnable () {
public void run () {
// is the menu inside the window of the parent component?
boolean previousContained = popupContained2(menu, popupParent);
menu.add(name);
if (previousContained) {
// this works fine
menu.pack ();
java.awt.Component c = menu.getParent();
if (c != null) {
c.validate();
}
} else {
// the problem is here:
menu.pack ();
// the call to pack moves the popup to coordinates [0,0] ????!!!!!
}
if (hack) {
// this hack redisplays the popup if it does not fit
// into the parent's window anymore
boolean nowContained = popupContained2(menu, popupParent);
if (previousContained != nowContained) {
System.out.println("changing state to " + nowContained);
menu.setVisible (false);
menu.setVisible (true);
}
}
}
});
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** @return true if the popup menu is contained in a window */
private static boolean popupContained2(JPopupMenu p, Component parent) {
try {
java.awt.Point popup = p.getLocationOnScreen ();
Window w = SwingUtilities.windowForComponent (parent);
Rectangle r = new Rectangle (popup, p.getSize ());
return w != null && w.getBounds ().contains (r);
} catch (java.awt.IllegalComponentStateException ex) {
return false;
}
}
/**
* @param args the command line arguments
*/
public static void main (String args[]) throws Exception {
MenuTest f = new MenuTest ();
b1 = new JButton ("Without hack");
b1.addActionListener(f);
b2 = new JButton ("With hack");
b2.addActionListener(f);
f.getContentPane ().setLayout (new java.awt.FlowLayout ());
f.getContentPane().add (b1);
f.getContentPane().add (b2);
f.setSize (300, 300);
f.show ();
}
public void actionPerformed(final java.awt.event.ActionEvent ev) {
new Thread ("Testing thread") {
public void run () {
showMenu (ev.getSource () == b2);
}
}.start ();
}
}
###@###.### 2001-08-15
Revised URL
http://www.netbeans.org/issues/show_bug.cgi?id=7872
ok on (presumably) all platforms. The problem demonstrates itself only on
Linux (tested on RedHat6.2) and with Gnome window manager.
The program tries to insert menu items into already displayed popup menu. It
works fine with JDK1.2.2 and the problem is introduced in JDK1.3.
I am not 100% sure but it seems to me that the call to
GlobalCursorManager.updateCursorImmediately();
on line 737 in java.awt.Container
surprisingly moves the heavyweight popup container to the location 0,0
on the screen. Next call to pack() (and from there to the mentioned
updateCursorImmediately) moves the window back to the correct
location.
Any fix or workaround would be highly appreciated since our bug #7872
http://www.netbeans.org/bugs-cgi/show_bug.cgi?id=7872
depends on this.
package test;
import java.awt.*;
import javax.swing.*;
public class MenuTest extends JFrame
implements java.awt.event.ActionListener {
private static JButton b1;
private static JButton b2;
/** Creates new MenuTest */
public MenuTest() {
super ("Test of menu");
}
/** Shows the menu.
* @param hack use hack or not?
*/
private void showMenu (final boolean hack) {
Dimension d = getSize ();
d.width /= 2;
d.height /= 2;
final JPopupMenu menu = new JPopupMenu ();
final Component popupParent = getContentPane();
menu.show(popupParent, d.width, d.height);
for (int i = 0; i < 19; i++) {
final String name = "Item " + i;
try {
SwingUtilities.invokeLater(new Runnable () {
public void run () {
// is the menu inside the window of the parent component?
boolean previousContained = popupContained2(menu, popupParent);
menu.add(name);
if (previousContained) {
// this works fine
menu.pack ();
java.awt.Component c = menu.getParent();
if (c != null) {
c.validate();
}
} else {
// the problem is here:
menu.pack ();
// the call to pack moves the popup to coordinates [0,0] ????!!!!!
}
if (hack) {
// this hack redisplays the popup if it does not fit
// into the parent's window anymore
boolean nowContained = popupContained2(menu, popupParent);
if (previousContained != nowContained) {
System.out.println("changing state to " + nowContained);
menu.setVisible (false);
menu.setVisible (true);
}
}
}
});
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/** @return true if the popup menu is contained in a window */
private static boolean popupContained2(JPopupMenu p, Component parent) {
try {
java.awt.Point popup = p.getLocationOnScreen ();
Window w = SwingUtilities.windowForComponent (parent);
Rectangle r = new Rectangle (popup, p.getSize ());
return w != null && w.getBounds ().contains (r);
} catch (java.awt.IllegalComponentStateException ex) {
return false;
}
}
/**
* @param args the command line arguments
*/
public static void main (String args[]) throws Exception {
MenuTest f = new MenuTest ();
b1 = new JButton ("Without hack");
b1.addActionListener(f);
b2 = new JButton ("With hack");
b2.addActionListener(f);
f.getContentPane ().setLayout (new java.awt.FlowLayout ());
f.getContentPane().add (b1);
f.getContentPane().add (b2);
f.setSize (300, 300);
f.show ();
}
public void actionPerformed(final java.awt.event.ActionEvent ev) {
new Thread ("Testing thread") {
public void run () {
showMenu (ev.getSource () == b2);
}
}.start ();
}
}
###@###.### 2001-08-15
Revised URL
http://www.netbeans.org/issues/show_bug.cgi?id=7872