【发布时间】:2015-10-23 17:01:11
【问题描述】:
我有一个 JPopupMenu,当按下 JButton 时会显示该菜单。此菜单包含一系列 JMenuItem,每个都与一个动作相关联,它们有时会发生变化。我遇到的问题是间歇性地没有绘制 JMenuItems,我只是得到一个灰色的 JPopupMenu,但是如果我将鼠标光标移到它们上面,这些项目就会出现。我认为问题可能在于更改后未正确重新绘制组件,但测试表明即使项目没有更改,问题也会继续发生。以下是相关代码:
if (!listChanged) {
myPopupMenu.show(myButton, x, y);
} else {
List<String> menuList = getMenuList();
MyData data = getData();
myPopupMenu.removeAll();
for (int i = 0; i < menuList.size(); i++) {
String name = menuList.get(i);
JMenuItem item = new JMenuItem(new MyMenuAction(this, name,
data, i));
item.addActionListener(this);
myPopupMenu.add(item);
myPopupMenu.validate();
}
myPopupMenu.repaint();
myPopupMenu.show(myButton, x, y);
}
...
private static class MyMenuAction extends AbstractAction {
private MyClass parent;
private int index;
private MyData data;
public MyMenuAction (MyClass parent, String name,
MyData data, int index) {
super(name);
this.parent = parent;
this.index = index;
this.data = data;
}
@Override
public void actionPerformed(ActionEvent e) {
Object[] actionParameters;
try {
actionParameters = data.getParameters(index);
} catch (ImmediateException e1) {
log(e1.getMessage(), "Error");
return;
}
parent.myButtonAction(actionParameters);
}
}
只是为了澄清一下,这些操作运行良好,JPopupMenu 和所有 JMenuItems 的 10 次中有 8 次被正确绘制,但我无法弄清楚为什么它们有时不出现(无论列表是否已更改或不)。任何帮助将不胜感激。
编辑: 好的,按照 Andrew Thompson 的建议,这里有一个简短的完整示例。许多方法已经被剥离,但基本的仍然存在。只需单击并按住“SHOW MENU”按钮即可显示 JPopupMenu。由于问题是间歇性的,因此可能需要多次执行,直到问题出现。
package main;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;
import javax.swing.UIManager;
public class MyClass implements ActionListener, MouseListener {
boolean listChanged = true;
boolean mousePressed = false;
long clickStart;
JPopupMenu myPopupMenu;
JButton myButton;
JFrame myFrame;
ArrayList<String> list;
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.start();
}
private void start() {
myFrame = new JFrame();
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.out.println(e.getClass().getName() + " " + e.getMessage());
}
startList();
myButton = new JButton("SHOW MENU");
myPopupMenu = new JPopupMenu();
JToolBar toolbar = new JToolBar();
toolbar.add(new JButton("Button1"));
toolbar.add(new JButton("Button2"));
toolbar.add(new JButton("Button3"));
toolbar.add(new JButton("Button4"));
toolbar.add(new JButton("Button5"));
toolbar.add(myButton);
myButton.addMouseListener(this);
toolbar.setBorder(BorderFactory.createEtchedBorder(1));
JPanel emptyPanel = new JPanel();
myFrame.add(toolbar, BorderLayout.PAGE_START);
myFrame.add(emptyPanel, BorderLayout.CENTER);
myFrame.pack();
myFrame.setExtendedState(myFrame.getExtendedState()
| JFrame.MAXIMIZED_BOTH);
myFrame.setVisible(true);
}
public void showMenu() {
if (!listChanged) {
myPopupMenu.show(myButton, 0, myButton.getHeight());
} else {
listChanged = false;
List<String> menuList = getMenuList();
MyData data = getData();
myPopupMenu.removeAll();
for (int i = 0; i < menuList.size(); i++) {
String name = menuList.get(i);
JMenuItem item = new JMenuItem(new MyMenuAction(this, name,
data, i));
item.addActionListener(this);
myPopupMenu.add(item);
myPopupMenu.validate();
}
myPopupMenu.repaint();
myPopupMenu.show(myButton, 0, myButton.getHeight());
}
}
private void startList() {
list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
list.add("Item 3");
list.add("Item 4");
list.add("Item 5");
}
private List<String> getMenuList() {
return list;
}
public void myButtonAction() {
Object[] defaultParameters = getDefaultParameters();
myButtonAction(defaultParameters);
}
private Object[] getDefaultParameters() {
// Placeholder
return null;
}
public void myButtonAction(Object[] actionParameters) {
// Placeholder
}
private MyData getData() {
// Placeholder
return new MyData();
}
private void changeList(List<String> newList) {
list.clear();
list.addAll(newList);
listChanged = true;
}
@Override
public void actionPerformed(ActionEvent e) {
// Placeholder
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getSource() == myButton) {
mousePressed = true;
clickStart = System.currentTimeMillis();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (this) {
while (mousePressed)
try {
this.wait(10);
if (System.currentTimeMillis() - clickStart > 300) {
MyClass.this.showMenu();
return;
}
} catch (InterruptedException e1) {
break;
}
MyClass.this.myButtonAction();
}
}
}).start();
}
}
@Override
public void mouseReleased(MouseEvent e) {
mousePressed = false;
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
private static class MyData {
public Object[] getParameters(int index) {
// Placeholder
return null;
}
}
private static class MyMenuAction extends AbstractAction {
private MyClass parent;
private int index;
private MyData data;
public MyMenuAction(MyClass parent, String name, MyData data, int index) {
super(name);
this.parent = parent;
this.index = index;
this.data = data;
}
@Override
public void actionPerformed(ActionEvent e) {
Object[] actionParameters;
try {
actionParameters = data.getParameters(index);
} catch (Exception e1) {
System.out.println(e1.getMessage());
return;
}
parent.myButtonAction(actionParameters);
}
}
}
【问题讨论】:
-
有时? 请参阅Initial Threads 并考虑
setComponentPopupMenu()。 -
"这里是相关代码:"如需更好的帮助,请尽快发帖minimal reproducible example或Short, Self Contained, Correct Example。
-
@trashgod 我的鼠标监听器上确实有一个线程,因为如果我按住它一段时间,它应该只显示 JPopupMenu(如果我只是单击,它会执行更简单的操作),但我不明白这怎么会导致我的问题,因为菜单已显示,但只有 JMenuItems 没有被绘制。
-
I do have a thread on my mouse listener,- 那么也许鼠标监听器就是问题所在。您是否意识到只有在同一位置生成 mousePressed 和 mouseReleased 事件时才会生成 mouseClick。因此,如果当您按住鼠标一段时间并且鼠标移动一个像素时,您将不会收到 mouseClicked 事件。这可能就是为什么它是随机的。所以基本上你发布的代码(可能)与问题无关。这就是为什么 Andres 要求的可运行示例应该随每个问题发布。 -
@camickr 我已经这样做了,我在回复垃圾神之前编辑了我的问题
标签: java swing jmenuitem jpopupmenu