0

我注意到,一旦我的 JPopupMenu 第一次变得可见,它的 MenuItems 就不会反映对它们所做的更改以用于下一次可见性。这是代码;

private static void addListener(final JPopupMenu popup, final String someLetter)
{
    popup.addPopupMenuListener(new PopupMenuListener(){            
        @Override
        public void popupMenuWillBecomeVisible(PopupMenuEvent evt)
        {
            JMenuItem menuItem3 = (JMenuItem)popup.getComponent(3); 
            String[] letters = {"A", "B", "C", "D"};
            ArrayList<String> lettersList = new ArrayList<String>();
            lettersList.addAll(Arrays.asList(letters));
            if(lettersList.contains(someLetter)){
                menuItem3.setEnabled(true);
            }
            else{
                menuItem3.setEnabled(false);
            }
        }
    });
}

通常,我希望每当弹出时,下面popupMenuWillBecomeVisible的行将始终执行。popupMenu但令我惊讶的是,它只在第一次工作,随后不测试指定为 enable 或 disable 的条件menuItem3。请有好心人帮帮兄弟!

4

2 回答 2

1

这对我来说似乎工作得很好。查看下面的示例,该示例显示 5 个菜单项并在每次执行右键单击时切换它们的“启用”:

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class TestPopupMenu {

    private void initUI() {
        final JFrame frame = new JFrame(TestPopupMenu.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        final JPopupMenu popup = new JPopupMenu();
        final List<JMenuItem> items = new ArrayList<JMenuItem>();
        for (int i = 0; i < 5; i++) {
            JMenuItem item = new JMenuItem(new AbstractAction("Action " + (i + 1)) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(popup, getValue(NAME) + " has been clicked");
                }
            });
            item.setEnabled(i % 2 == 0);
            items.add(item);
            popup.add(item);
        }
        popup.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                for (JMenuItem item : items) {
                    item.setEnabled(!item.isEnabled());
                }
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {

            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {

            }
        });
        panel.setComponentPopupMenu(popup);
        frame.add(panel);
        frame.setSize(300, 200);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestPopupMenu().initUI();
            }
        });
    }
}
于 2013-03-14T22:39:11.987 回答
1

感谢@mKorbel 推动我在此过程中尝试编写 SSCCE cos,我找到了解决方案。无论如何,这是我的 SSCCE,它可能对其他人有用。谁知道?只需复制并运行即可查看其工作原理。

(注意:代码不是很短,因为我打算在此之后提出次要问题)

import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class CustomPopup extends JPopupMenu
{
    private JMenuItem menuItem1 = new JMenuItem("One");
    private JMenuItem menuItem2 = new JMenuItem("Two");
    private JMenuItem menuItem3 = new JMenuItem("Three");
    private JMenuItem menuItem4 = new JMenuItem("Four");
    private JMenuItem menuItem5 = new JMenuItem("Five");

    public CustomPopup()
    {
        this.add(menuItem1);
        this.add(menuItem2);
        this.add(menuItem3);
        this.add(menuItem4);
        this.add(menuItem5);
        addListeners(this);
    }

    private  void addListeners(final JPopupMenu popup /*, final String someLetter*/)
    {
        popup.addPopupMenuListener(new PopupMenuListener(){            
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent evt)
            {
                JMenuItem menuItem = (JMenuItem)popup.getComponent(3); 
                String[] letters = {"A", "B", "C", "D"};
                ArrayList<String> lettersList = new ArrayList<String>();
                lettersList.addAll(Arrays.asList(letters));
                String someLetter = getRandomAlphabet();
                if(lettersList.contains(someLetter)){
                    menuItem.setEnabled(true);
                }
                else{
                    menuItem.setEnabled(false);
                }
            }
            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent evt){
                // No Override
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent evt){
                // No Override
            }
        });
    }

    private  String getRandomAlphabet()
    {
        String alpha = "";
        String Alphas[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"};
        double bigNum = Math.random() * 1000000;
        String str = String.valueOf(bigNum);
        int idx = Integer.valueOf(String.valueOf(str.charAt(str.length() - 1)));
        if(idx < 6)
        {
            alpha = Alphas[idx];
        }
        else
        {
            alpha = Alphas[idx - 5];
        }
        return alpha;
    }

    public static void main(String[] args)
    {
        /*try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }*/

        JPanel panel = new JPanel();
        JPopupMenu popupMenu = new CustomPopup();
        panel.setComponentPopupMenu(popupMenu);
        panel.setLayout(new GridBagLayout());

        /*JButton button = new JButton("Action");
        button.setSize(new Dimension(60, 20));
        button.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e)
            {
                JOptionPane.showMessageDialog(null, "Button was clicked");
            }
        });
        panel.add(button);*/

        JFrame frame = new JFrame("popupTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(200, 200));
        frame.add(panel);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

问题:现在这可以满足我的要求(即menuItem4根据某些指定计算的随机结果动态启用和禁用getRandomAlphabet()),我查看了@Guillaume Polet 的 Lovely 实现并对其进行了测试。UIManager非常好......所以我决定添加一个按钮并测试我在使用不是本机 Java 默认值时遇到的最烦人的问题之一......同样的事情发生了!

我是什么意思?当 LnF 不是默认值Metal时,在显示 popupMenu 后在任何其他 Actionable 组件上单击 popupMenu 外部在第一次单击时不起作用(这只会将弹出窗口设置为不可见)。然后您必须再次(第二次)单击该组件,然后才能触发其 Action... 很烦人不是吗?

要了解这种情况,只需取消注释UIManager上面的代码部分(我从@Guillaume Polet 的漂亮解决方案中获取)并取消注释Button我添加的部分,然后运行程序并查看当您尝试单击时会发生什么显示后立即按钮popupMenu。有趣的是,在使用 Java 的默认 Metal LnF 时不会出现这个问题

我已经在 Windows 7 上使用系统默认外观解决了这个问题,但无济于事,所以我决定让睡狗撒谎......但老实说,我认为有一个解决这个问题......我知道一定有人对这个东西有破解......代码块,方向,链接,任何解决这个问题的任何地方都会让我感到非常高兴。谢谢好心人!

于 2013-03-15T02:47:26.987 回答