英文:
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();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论