我注意到,一旦我的JPopupMenu第一次可见,它的菜单项不反映对它们的下一次可见性所做的更改。下面是代码;
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
弹出时执行。但令我惊讶的是,它只适用于第一次,随后不测试指定的条件,以启用或禁用menuItem3
。拜托有人帮帮我的兄弟吧!
这对我来说似乎工作得很好。看看下面的例子,它显示了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();
}
});
}
}
感谢@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()
),我看了@纪尧姆波莱的可爱的实现和测试它。很好……所以我只是决定添加一个按钮,并测试一个最恼人的问题,我曾经有过使用UIManager
,不是原生Java默认弹出窗口时…同样的事情发生了!
我是什么意思?当LnF不是默认的Metal
时,在弹出菜单显示后,单击任何其他可操作组件的弹出菜单外,第一次单击不起作用(这只会设置不可见的弹出)。然后你必须再次点击组件(第二次),才能触发它的Action……很烦人,不是吗?
为了感受这种场景,只需取消上面代码的UIManager
部分的注释(我从@Guillaume Polet的漂亮解决方案中获得的),并取消我添加的Button
部分的注释,然后运行程序,看看当您尝试在popupMenu
显示后立即单击按钮时会发生什么。有趣的是,这个问题不会发生在使用Java默认的Metal
时。我在Windows 7上使用系统默认的外观和感觉来解决这个问题,但无济于事,所以我决定不要自找麻烦……但老实说,我认为有一个解决办法……我知道肯定有人能破解这玩意……代码块,方向,链接,任何解决这个问题的地方都会让我非常高兴。谢谢善良的人们!