Не удается выполнить действие JMenuItem в JPopupMenu без получения java.lang.Исключение ClassCastException

#java #swing #jframe #awt

#java #swing #jframe #awt

Вопрос:

Я пытаюсь скрыть окно JFrame и создавать значок в трее всякий раз, когда оно закрывается, вместо выхода. Затем значок в трее должен содержать два пункта меню, которые могут снова сделать окно JFrame видимым и полностью закрыть его соответственно. Первое работает должным образом, но при попытке выполнить действие из JMenuItem из JPopupMenu значка в трее выдается следующее исключение:

 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)
  

Вот соответствующий раздел кода, контролирующий поведение минимизации и 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() amp; (~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);
    }
});
  

Код, вероятно, не самый красивый, но я все еще не понимаю, что заставляет Java генерировать это исключение. Есть ли какое-то конкретное место, где я что-то напутал?

Комментарии:

1. чего вы ожидали от этого в своем коде: ((JFrame)e.getSource())? Вы пытаетесь принудительно преобразовать результат e.getSource() в JFrame, но e.getSource() не возвращает JFrame.

2. JFrame вряд ли является источником события

Ответ №1:

Как отметили комментаторы, JFrame определенно не является источником вашего события.

Если вы хотите, чтобы этот точный код не вызывал исключение, вы могли бы просто перехватывать исключение всякий раз, когда вы вызываете приведение к JFrame :

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

Что вы, вероятно, хотите сделать, так это получить, Component который является источником события, а затем получить родительский элемент Container этого Component .

Это может выглядеть примерно так:

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

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

        frame.setExtendedState(JFrame.NORMAL);
    }
}
  

Ответ №2:

Первое работает должным образом, но при попытке выполнить действие из JMenuItem из JPopupMenu значка в трее, я выдаю следующее исключение:…

Первое работает, потому что вы добавляете 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();