未触发 JPopupMenu 操作

JPopupMenu action not triggered

这是我所拥有的(简化版)。 (我是这样找到代码的):

class CustomPopup extends JPopupMenu {
    public CustomPopup() {}

    @Override
    public void setVisible(boolean visible)
    {
        // Case 1:
        //if (visible) super.setVisible(visible);
        // Case 2:
        super.setVisible(visible);
    }
}

class CustomPanel extends JPanel {
    // .../...
    public CustomPanel() {
        setSize(200, 200);
        addMouseListener( new MouseAdapter(){
            @Override
            public void mousePressed( MouseEvent e ){
                onMousePressed( e );
            }
        });

    }

    public void onMousePressed( MouseEvent e )
    {
        JPopupMenu pop = new JPopupMenu();

        pop.add( new AbstractAction( "foo" )
        {
            @Override
            public void actionPerformed( ActionEvent e )
            {
                // do stuff
                System.out.println("this is executed");
            }
        });
        pop.show( e.getComponent(), e.getX(), e.getY() );
    }
}

public class TestPopup extends JFrame {
    CustomPanel _pp;
    CustomPopup _cpop;

    public TestPopup () {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(333, 333);
        _cpop = new CustomPopup();
        _pp = new CustomPanel();
        _cpop.add(_pp);

        addMouseListener( new MouseAdapter(){
            @Override
            public void mousePressed( MouseEvent e ){
                _cpop.show(e.getComponent(), 0, 0);
            }
        });
    }
    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                (new TestPopup()).setVisible(true);
            }
        });
    }
}

弹出菜单显示自定义面板。与它交互时,它会显示带有选项列表的经典弹出菜单。

我的问题是 CustomPopup 没有按预期自行关闭。罪魁祸首显然是 setVisible 的覆盖,但是如果我删除覆盖方法(或注释掉条件),我会遇到另一个问题:永远不会调用添加到 pop 上的 actionPerformed 方法。

第一种情况:

  1. CustomPopup 打开
  2. 我点击里面的东西
  3. JPopupMenu 打开 并且 CustomPopup 保持可见
  4. 我点击了新菜单的一个项目
  5. 触发Action

第二种情况:

  1. CustomPopup 打开
  2. 我点击里面的东西
  3. JPopupMenu打开CustomPopup隐藏
  4. 我点击了新菜单的一个项目
  5. Action触发

我的结论是 CustomPopup 必须可见才能触发操作,即使我真的不明白为什么。所以我的问题是:如何以不破坏默认 JPopupMenu 行为的方式保持 CustomPopup 打开,或者如何在隐藏 CustomPopup 的情况下正确触发操作?

看起来弹出窗口的父级必须可见才能触发操作(对我来说听起来很合理)。所以除了最后一步之外,你已经做了所有让它工作的事情:自己关闭自定义弹出窗口。这是代码:

class CustomPopup extends JPopupMenu {
    public CustomPopup() {}

    @Override
    public void setVisible(boolean visible)
    {
        // Case 1:
        if (visible) super.setVisible(visible);
        // Case 2:
//        super.setVisible(visible);
    }
    public void makeInvisible() {
        super.setVisible(false);
    }
}

class CustomPanel extends JPanel {
    // .../...
    public CustomPanel() {
        setSize(200, 200);
        addMouseListener( new MouseAdapter(){
            @Override
            public void mousePressed( MouseEvent e ){
                onMousePressed( e );
            }
        });

    }

    public void onMousePressed( MouseEvent e )
    {
        JPopupMenu pop = new JPopupMenu();

        pop.add( new AbstractAction( "foo" )
        {
            @Override
            public void actionPerformed( ActionEvent e )
            {
                // do stuff
                System.out.println("this is executed");
                Component comp = (Component) e.getSource();
                if (comp != null && comp.getParent() instanceof JPopupMenu) {
                    JPopupMenu popupMenu = (JPopupMenu) comp.getParent();
                    if (popupMenu.getInvoker() instanceof CustomPanel) {
                        CustomPopup cpop = (CustomPopup) popupMenu.getInvoker().getParent();
                        cpop.makeInvisible();
                    }
                }
            }
        });
        pop.show( e.getComponent(), e.getX(), e.getY() );
    }
}

public class TestPopup extends JFrame {
    CustomPanel _pp;
    CustomPopup _cpop;

    public TestPopup () {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(333, 333);
        _cpop = new CustomPopup();
        _pp = new CustomPanel();
        _cpop.add(_pp);

        addMouseListener( new MouseAdapter(){
            @Override
            public void mousePressed( MouseEvent e ){
                _cpop.show(e.getComponent(), e.getX(), e.getY());
            }
        });
    }
    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                (new TestPopup()).setVisible(true);
            }
        });
    }
}