无法在不抛出java.lang.ClassCastException的情况下执行JPopupMenu中的JMenuItem操作。

huangapple go评论72阅读模式
英文:

Can't perform JMenuItem action in JPopupMenu without getting thrown a java.lang.ClassCastException

问题

以下是翻译好的内容:

尝试在 JFrame 窗口关闭时隐藏它并创建一个托盘图标而不是退出应用然后托盘图标应该有两个菜单项一个用于重新显示 JFrame 窗口另一个用于完全退出应用前者正常工作但是当尝试从托盘图标的 JPopupMenu 中的 JMenuItem 执行操作时抛出以下异常

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: class javax.swing.JMenuItem cannot be cast to class javax.swing.JFrame (javax.swing.JMenuItem 和 javax.swing.JFrame 在加载器 "bootstrap" 的 java.desktop 模块中)
        at Hierophant$5.actionPerformed(Hierophant.java:94)
        ...

以下是控制最小化行为和 JPopupMenu 的相关代码部分它在一个继承自 JFrame 的公共类中的一个无参数格式化方法中运行

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

setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);

SystemTray tray = SystemTray.getSystemTray();
JPopupMenu menu = new JPopupMenu();
JMenuItem show = new JMenuItem("Show");
JMenuItem exit = new JMenuItem("Exit");

icon = Toolkit.getDefaultToolkit().getImage("icon.png");
trayIcon = new TrayIcon(icon, "Hierophant");
show.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        ((JFrame)e.getSource()).setExtendedState(JFrame.NORMAL);
        ((JFrame)e.getSource()).setExtendedState(((JFrame)e.getSource()).getExtendedState() & (~JFrame.ICONIFIED));
        pack();
    }
});
exit.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        ((JFrame)e.getSource()).dispose();
    }
});
menu.add(show);
menu.addSeparator();
menu.add(exit);
trayIcon = new TrayIcon(icon, "Hierophant");
trayIcon.setImageAutoSize(true);
trayIcon.addMouseListener(new MouseAdapter() {
    public void showPopup(MouseEvent e) {
        if (e.isPopupTrigger()) {
            menu.setLocation(e.getX(), e.getY());
            menu.setInvoker(menu);
            menu.setVisible(true);
        }
    }
    @Override
    public void mouseReleased(MouseEvent e) {
        showPopup(e);
    }
    public void mousePressed(MouseEvent e) {
        showPopup(e);
    }
});
try {
    tray.add(trayIcon);
} catch (AWTException e) {
    e.printStackTrace();
}
addWindowListener(new WindowAdapter() {
    @Override
    public void windowClosing(WindowEvent e) {
        ((JFrame)e.getSource()).setExtendedState(JFrame.ICONIFIED);
        ((JFrame)e.getSource()).setExtendedState(((JFrame)e.getSource()).getExtendedState() | JFrame.ICONIFIED);
    }
});
英文:

I am attempting to have a JFrame window hide itself and create a tray icon whenever it is closed instead of exiting. The tray icon should then have two menu items able to make the JFrame window visible again and to exit it entirely respectively. The former works properly, but when attempting to perform an action from a JMenuItem from the tray icon's JPopupMenu, I am thrown the following exception:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: class javax.swing.JMenuItem cannot be cast to class javax.swing.JFrame (javax.swing.JMenuItem and javax.swing.JFrame are in module java.desktop of loader 'bootstrap')
at Hierophant$5.actionPerformed(Hierophant.java:94)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369)
at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1020)
at java.desktop/javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1064)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6636)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
at java.desktop/java.awt.Component.processEvent(Component.java:6401)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5012)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4844)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4919)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4548)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4489)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2764)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4844)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:772)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:743)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Here is the relevant section of code controlling minimization behavior and the JPopupMenu. It's being run in a method with no parameter formatters inside a public class extending JFrame.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
SystemTray tray = SystemTray.getSystemTray();
JPopupMenu menu = new JPopupMenu();
JMenuItem show = new JMenuItem("Show");
JMenuItem exit = new JMenuItem("Exit");
icon = Toolkit.getDefaultToolkit().getImage("icon.png");
trayIcon = new TrayIcon(icon, "Hierophant");
show.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
((JFrame)e.getSource()).setExtendedState(JFrame.NORMAL);
((JFrame)e.getSource()).setExtendedState(((JFrame)e.getSource()).getExtendedState() & (~JFrame.ICONIFIED));
pack();
}
});
exit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
((JFrame)e.getSource()).dispose();
}
});
menu.add(show);
menu.addSeparator();
menu.add(exit);
trayIcon = new TrayIcon(icon, "Hierophant");
trayIcon.setImageAutoSize(true);
trayIcon.addMouseListener(new MouseAdapter() {
public void showPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
menu.setLocation(e.getX(), e.getY());
menu.setInvoker(menu);
menu.setVisible(true);
}
}
@Override
public void mouseReleased(MouseEvent e) {
showPopup(e);
}
public void mousePressed(MouseEvent e) {
showPopup(e);
}
});
try {
tray.add(trayIcon);
} catch (AWTException e) {
e.printStackTrace();
}
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
((JFrame)e.getSource()).setExtendedState(JFrame.ICONIFIED);
((JFrame)e.getSource()).setExtendedState(((JFrame)e.getSource()).getExtendedState() | JFrame.ICONIFIED);
}
});

The code probably isn't the prettiest, but I'm still at a loss as to what is causing Java to throw this exception. Is there some place in particular where I've messed up?

答案1

得分: 1

正如评论者所指出的那样,JFrame 显然不是您事件的来源。

如果您希望这段精确的代码不抛出异常,您可以在调用转换为 JFrame 的地方捕获异常:

try
{
    (JFrame) e.getSource(); 
}
catch(ClassCastException e)
{
    // 无操作
}

您可能想要做的是获取作为事件源的 Component,然后获取该 Component 的父 Container

代码可能如下所示:

if(e.getSource() instanceof Component)
{
    Component component = (Component) e.getSource();

    if(component.getParent() instanceof JFrame)
    {
        JFrame frame = (JFrame) component;

        frame.setExtendedState(JFrame.NORMAL);
    }
}
英文:

As commenters have pointed out, JFrame definitely isn't the source of your event.

If you want this exact code to not throw the exception, you could simply catch the exception whenever you call the cast to JFrame:

try
{
    (JFrame) e.getSource(); 
}
catch(ClassCastException e)
{
    // nothing
}

What you probably want to do is getting the Component which is the event source and then get the Parent Container of that Component.

It could look something like this:

if(e.getSource() instanceof Component)
{
    Component component = (Component) e.getSource();

    if(component.getParent() instanceof JFrame)
    {
        JFrame frame = (JFrame) component;

        frame.setExtendedState(JFrame.NORMAL);
    }
}

答案2

得分: 1

> 前者可以正常工作,但是当尝试从托盘图标的JPopupMenu中执行JMenuItem的操作时,会抛出以下异常:...

前者可以正常工作是因为您将WindowListener添加到了JFrame中。

后者无法正常工作是因为您将ActionListener添加到了JMenuItem中。

> ... 在线程“AWT-EventQueue-0”中的异常java.lang.ClassCastException:无法将类javax.swing.JMenuItem转换为类javax.swing.JFrame

您对这个异常感到困惑的是什么?如果您点击一个JMenuItem,为什么认为您可以将ActionEvent的源视为JFrame?

您在论坛中的问题应该是:如何在给定JMenuItem的情况下访问框架?

针对这个问题,您可以尝试:

JMenuItem menuItem = (JMenuItem)e.getSource();
Window window = SwingUtilitiels.windowForComponent(menuItem);
window.dispose();
英文:

> The former works properly, but when attempting to perform an action from a JMenuItem from the tray icon's JPopupMenu, I am thrown the following exception:...

The former works because you add the WindowListener to the JFrame.

The latter doesn't work because you add the ActionListener to the JMenuItem.

> ... Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: class javax.swing.JMenuItem cannot be cast to class javax.swing.JFrame

What do you find confusing about that Exception? If you click on a JMenuItem why do you think you can treat the source of ActionEvent as a JFrame?

Your question in the forum should be: How can I access the frame given a JMenuItem?

In response to that your can try:

JMenuItem menuItem = (JMenuItem)e.getSource();
Window window = SwingUtilitiels.windowForComponent( menuItem );
window.dispose();

huangapple
  • 本文由 发表于 2020年9月3日 15:33:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/63718888.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定