Java JPopupMenu bug [英] Java JPopupMenu bug
问题描述
好像我在Java中发现了一个错误:
Seems like I've found a bug in Java:
我需要创建 JFrame
透明背景,现在我需要为某些用户操作显示 JPopupMenu
。当 JPopupMenu
完全位于 JFrame
内时,它可以正常工作。但是当 JPopupMenu
部分在 JFrame
之外时,没有任何项目可见。
I need to create the JFrame
with a transparent background and now I need to show the JPopupMenu
for some user actions. It works fine when JPopupMenu
is housed fully inside a JFrame
. But when the JPopupMenu
is partly outside the JFrame
, no item is visible.
SSCCE:
public class PopupTest {
public static void main(String[] a) {
final JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createLineBorder(Color.RED));
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
JPopupMenu menu = new JPopupMenu();
for (int i = 0 ; i < 10; i++) {
menu.add(String.valueOf(i));
}
menu.show(panel, e.getX(), e.getY());
}
}
});
frame.setContentPane(panel);
frame.setUndecorated(true);
frame.setBackground(new Color(50, 50, 50, 200));
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.setVisible(true);
}
});
}
}
有谁知道如何解决这个问题?
Does anyone know how to solve this?
PS: JDK 7u40,Win x64
PS: JDK 7u40, Win x64
推荐答案
这是Oracle JDK 7中的错误(顺便说一下,它无法在Open JDK 7中重现)。
This is bug in Oracle JDK 7 (it cannot be reproduced in Open JDK 7 by the way).
要解决这个问题,你可以做一个解决方法(是的,这是只是一个解决方法,不能保证它不会破坏某些Java更新),因此为弹出菜单创建的窗口一旦显示就会变为非不透明,然后它将正确显示。至少现在(是。以下是Java 7及更高版本的完成方式:
To fix this you can make a workaround (yes, this is just a workaround, there is no guarantees that it won't break with some Java update) so that the window created for popup-menu will become non-opaque as soon as it shows up, then it will be displayed properly. Atleast for now. Here is how this can be done for Java version 7 and later:
PropertyChangeListener propertyChangeListener = new PropertyChangeListener ()
{
@Override
public void propertyChange ( final PropertyChangeEvent evt )
{
if ( evt.getNewValue () == Boolean.TRUE )
{
// Retrieving popup menu window (we won't find it if it is inside of parent frame)
final Window ancestor = getWindowAncestor ( popupMenu );
if ( ancestor != null && ancestor.getClass ().getCanonicalName ().endsWith ( "HeavyWeightWindow" ) )
{
// Checking that parent window for our window is opaque, only then setting opacity
final Component parent = ancestor.getParent ();
if ( parent != null && parent instanceof Window && parent.getBackground ().getAlpha () == 0 )
{
// Making popup menu window non-opaque
ancestor.setBackground ( new Color ( 0, 0, 0, 0 ) );
}
}
}
}
private Window getWindowAncestor ( Component component )
{
if ( component == null )
{
return null;
}
if ( component instanceof Window )
{
return ( Window ) component;
}
for ( Container p = component.getParent (); p != null; p = p.getParent () )
{
if ( p instanceof Window )
{
return ( Window ) p;
}
}
return null;
}
};
popupMenu.addPropertyChangeListener ( "visible", propertyChangeListener );
如果你还想支持JDK 6版本,你将不得不付出更多的努力,因为那些代码甚至不会在早期的JDK版本上编译(早期版本的Window中没有set / getBackground方法)。
You will have to put some more effort if you also want to support JDK 6- versions because that code won't even compile on earlier JDK versions (there are no "set/getBackground" methods in Window in earlier versions).
这篇关于Java JPopupMenu bug的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!