gpt4 book ai didi

java - JMenuItem 的 ActionListener 不工作

转载 作者:行者123 更新时间:2023-11-30 08:32:45 28 4
gpt4 key购买 nike

我正在做一个个人项目,按钮的部分功能是当它们被右键单击时,它们会显示一个 PopMenu。该代码在昨天之前一直有效,但今天我试图让它变得更 OO 而现在,虽然菜单确实显示了,但当我单击 MenuItems 时没有任何反应。不幸的是,我没有版本控制,所以我没有旧版本的副本。

代码如下:

这是 PopUpMenu

public class PopUpMenu extends JPopupMenu {
private Container parent;

public PopUpMenu(MenuItem[] menuItems) {
super();
for (MenuItem item : menuItems) {
add(item);
}
}

public Container getParent() {
return parent;
}

public void setParent(Container parent) {
this.parent = parent;
parent.addMouseListener(new PopUpListener(this));
}

}

这是实际的 MenuItem

public class MenuItem extends JMenuItem {
private String methodName;

public MenuItem(String methodName, String text) {
super(text);
setMethodName(methodName);
setFocusable(true);
addActionListener(new MenuItemListener());
}

public String getMethodName() {
return methodName;
}

public void setMethodName(String methodName) {
this.methodName = methodName;
}

}

这是 MenuItemActionListener

public class MenuItemListener extends IListener {

protected void action(ActionEvent event) {
Object source = event.getSource();
if (source instanceof MenuItem) {
MenuItem item = (MenuItem) source;
Container parent = item.getParent();
if (parent instanceof PopUpMenu) {
PopUpMenu menu = (PopUpMenu) parent;
Container container = menu.getParent();
try {
String name = item.getMethodName();
Method method = container.getClass().getMethod(name);
method.invoke(container);
} catch (Exception e) {
}
}
}
}

}

这是 PopUpMenuActionListener

public class PopUpListener extends MouseAdapter {
private PopUpMenu menu;

public PopUpListener(PopUpMenu menu) {
setMenu(menu);
}

public void mouseReleased(MouseEvent event) {
if (event.isPopupTrigger()) {
menu.show(event.getComponent(), event.getX(), event.getY());
}
}

public PopUpMenu getMenu() {
return menu;
}

public void setMenu(PopUpMenu menu) {
this.menu = menu;
}

}

这里是抽象类 IListener

public abstract class IListener implements ActionListener {
private boolean keyboardSensitive;

public IListener() {
setKeyboardSensitive(false);
}

@Override
public void actionPerformed(ActionEvent event) {
if ((event.getModifiers() != 0) || isKeyboardSensitive()) {
action(event);
}
}

protected abstract void action(ActionEvent event);

public boolean isKeyboardSensitive() {
return keyboardSensitive;
}

public void setKeyboardSensitive(boolean keyboardSensitive) {
this.keyboardSensitive = keyboardSensitive;
}

}

经过一些测试后,我发现 ActionListener 实际上是由按下的键激活的,而不是由鼠标的任何按钮激活的,(通过在调试期间删除 if 发现)这不是很有帮助因为正如您在 IListener 类中看到的那样,我不想接受来自键盘的任何事件。

IListener 也是我在我的程序中使用的所有其他 ActionListeners 的基础,它似乎对它们工作良好。

所以基本上我的问题是:我需要修复什么才能通过鼠标点击激活 MenuItemListener

最佳答案

PopUpMenu 中移除 getParent 方法

public class PopUpMenu extends JPopupMenu {
private Container parent;

public PopUpMenu(MenuItem[] menuItems) {
super();
for (MenuItem item : menuItems) {
add(item);
}
}

public void setParent(Container parent) {
this.parent = parent;
parent.addMouseListener(new PopUpListener(this));
}

}

此方法将覆盖 java.awt.Component.getParent() 中定义的 getParent。我想这会导致意外行为。

编辑

I'm overriding that method on purpose. But I still tried to remove it to see if that would fix the problem. Unfortunately, it did not.

您可以覆盖该方法,但必须确保 Component.getParent method's contract .

PopUpMenu 不是容器 parent 的子项。我的意思是,如果 PopUpMenu 返回容器 parent,容器也应该知道 PopUpMenu 是它的子容器。例如。 Container.getCompnents()应包含 PopUpMenu。这就是契约(Contract)。

但这对你的情况没有帮助,因为它并不真正想要创建组件父/子关系。您只想保留对要调用某些 method.invoke(container); 的某个对象的引用。

此示例基于您的代码以及我在上面建议的修复。我已将所有内容放在一个编译单元中以提供 MVCE :

import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import javax.swing.*;

public class Main {

public static void main(String[] args) {
JFrame frame = createFrame();

MenuItem menuItem1 = new MenuItem("getForeground", "Foreground Color");
MenuItem menuItem2 = new MenuItem("getBackground", "Background Color");
PopUpMenu popUpMenu = new PopUpMenu(new MenuItem[] { menuItem1, menuItem2 });
popUpMenu.setParent(frame);

frame.setVisible(true);
}

private static JFrame createFrame() {
JFrame frame = new JFrame();
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}

}


class PopUpMenu extends JPopupMenu {

private Container parent;

public PopUpMenu(MenuItem[] menuItems) {
super();
for (MenuItem item : menuItems) {
add(item);
}
}

public Container getParentComponent() {
// another name because I don't want to override getParent()
// Try to rename this method to getParent to see
// that it will not work
return parent;
}

public void setParent(Container parent) {
this.parent = parent;
parent.addMouseListener(new PopUpListener(this));
}

}

class MenuItemListener extends IListener {

protected void action(ActionEvent event) {
Object source = event.getSource();
if (source instanceof MenuItem) {
MenuItem item = (MenuItem) source;
Container parent = item.getParent();
if (parent instanceof PopUpMenu) {
PopUpMenu menu = (PopUpMenu) parent;
Container container = menu.getParentComponent();
try {
String name = item.getMethodName();
Method method = container.getClass().getMethod(name);
Object invoke = method.invoke(container);
JOptionPane.showMessageDialog(container, invoke);
} catch (Exception e) {
}
}
}
}

}


abstract class IListener implements ActionListener {
private boolean keyboardSensitive;

public IListener() {
setKeyboardSensitive(false);
}

@Override
public void actionPerformed(ActionEvent event) {
if ((event.getModifiers() != 0) || isKeyboardSensitive()) {
action(event);
}
}

protected abstract void action(ActionEvent event);

public boolean isKeyboardSensitive() {
return keyboardSensitive;
}

public void setKeyboardSensitive(boolean keyboardSensitive) {
this.keyboardSensitive = keyboardSensitive;
}

}

class MenuItem extends JMenuItem {
private String methodName;

public MenuItem(String methodName, String text) {
super(text);
setMethodName(methodName);
setFocusable(true);
addActionListener(new MenuItemListener());
}

public String getMethodName() {
return methodName;
}

public void setMethodName(String methodName) {
this.methodName = methodName;
}

}

class PopUpListener extends MouseAdapter {
private PopUpMenu menu;

public PopUpListener(PopUpMenu menu) {
setMenu(menu);
}

@Override
public void mousePressed(MouseEvent event) {
if (event.isPopupTrigger()) {
menu.show(event.getComponent(), event.getX(), event.getY());
}

}

public void mouseReleased(MouseEvent event) {
if (event.isPopupTrigger()) {
menu.show(event.getComponent(), event.getX(), event.getY());
}
}

public PopUpMenu getMenu() {
return menu;
}

public void setMenu(PopUpMenu menu) {
this.menu = menu;
}

}

这是相同逻辑的重构版本,它不需要很多专门的(扩展的)类,如 PopUPMenuMenuItem

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.*;
import java.text.MessageFormat;

import javax.swing.*;

public class Main {

public static void main(String[] args) {
JFrame frame = createFrame();

JMenuItem foregroundMenuItem = createMenuItem(frame, "getForeground", "Foreground Color");
JMenuItem backgroundMenuItem = createMenuItem(frame, "getBackground", "Background Color");

JPopupMenu popupMenu = new JPopupMenu();

popupMenu.add(foregroundMenuItem);
popupMenu.add(backgroundMenuItem);

PopUpListener popUpListener = new PopUpListener(popupMenu);
frame.addMouseListener(popUpListener);

frame.setVisible(true);
}

private static JMenuItem createMenuItem(Object invocationTarget, String methodName, String actionName) {
MethodInvocationAction methodInvocationAction = new MethodInvocationAction(invocationTarget, methodName);
methodInvocationAction.putValue(Action.NAME, actionName);

JMenuItem menuItem = new JMenuItem(methodInvocationAction);
return menuItem;
}

private static JFrame createFrame() {
JFrame frame = new JFrame();
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
return frame;
}

}

class MethodInvocationAction extends AbstractAction {

private Object targetObj;
private Method targetMethod;

private boolean keyboardSensitive;

public MethodInvocationAction(Object targetObj, String methodName) {
this.targetObj = targetObj;
try {
targetMethod = targetObj.getClass().getMethod(methodName);
} catch (NoSuchMethodException | SecurityException e) {
String msg = MessageFormat.format("{0} does not have a method named {1}", targetObj, methodName);
throw new RuntimeException(msg, e);
}
}

public boolean isKeyboardSensitive() {
return keyboardSensitive;
}

public void setKeyboardSensitive(boolean keyboardSensitive) {
this.keyboardSensitive = keyboardSensitive;
}

@Override
public void actionPerformed(ActionEvent event) {
if ((event.getModifiers() != 0) || isKeyboardSensitive()) {
performAction(event);
}
}

public void performAction(ActionEvent e) {
try {
Object invoke = targetMethod.invoke(targetObj);
JOptionPane.showMessageDialog(null, invoke);
} catch (Exception exception) {
showException(exception);
}
}

private void showException(Exception e1) {
StringWriter exceptionStackTraceWriter = new StringWriter();
e1.printStackTrace(new PrintWriter(exceptionStackTraceWriter));
String exceptionStackTrace = exceptionStackTraceWriter.toString();

JTextArea exceptionStackTraceTextComponent = new JTextArea();
exceptionStackTraceTextComponent.setText(exceptionStackTrace);

JScrollPane scrollPane = new JScrollPane(exceptionStackTraceTextComponent);
scrollPane.setPreferredSize(new Dimension(800, 600));

JOptionPane.showMessageDialog(null, scrollPane, e1.getLocalizedMessage(), JOptionPane.ERROR_MESSAGE);
}
}

class PopUpListener extends MouseAdapter {
private JPopupMenu menu;

public PopUpListener(JPopupMenu menu) {
this.menu = menu;
}

public void mousePressed(MouseEvent event) {
handlePopupEvent(event);
}

public void mouseReleased(MouseEvent event) {
handlePopupEvent(event);
}

private void handlePopupEvent(MouseEvent event){
if (event.isPopupTrigger()) {
menu.show(event.getComponent(), event.getX(), event.getY());
}
}

}

关于java - JMenuItem 的 ActionListener 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39913371/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com