当前位置: 首页 > 知识库问答 >
问题:

我怎么知道什么时候显示一个JMenuItem?添加一个ComponentListener和使用组件显示不工作

白淇
2023-03-14

下面是一个完整的编译运行失败的例子,说明了我的问题。JMenuItem扩展了JComponent。当添加到JPopupMenu并显示在上下文菜单中时......它是......良好的......SHOWN,但是没有调用组件Shown方法。我如何知道JMenuItem何时显示?我需要从JMenuItem本身中知道。我正在创建这个JMenuItem并将其交给一个更大的框架。我不知道或控制JPopupMenu、容器或任何其他组件。当我的JMenuItem显示时,我必须根据应用程序的上下文和当前状态更新其文本。我如何知道它何时显示?

在下面的示例中,文本“显示的组件”在任何情况下都不会打印。右键单击JPanel以获取上下文菜单,您将看到JMenuItem文本“回复嗨”,但现在输出到控制台。

我运行在macOS 11.5.2 Big Sur和JDK 11.0.6 LTS(来自Oracle)上。

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

public class JMenuItemListeners {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        frame.setMinimumSize(new Dimension(800, 600));
        panel.setLayout(new BorderLayout());
        panel.add(new JLabel("Hello World... right click me."),
                BorderLayout.CENTER);
        //========================================
        JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem menuItem = new JMenuItem("Reply Hi");
        menuItem.addComponentListener(
        new ComponentListener() {
            @Override
            public void componentResized(ComponentEvent e) {}
            @Override
            public void componentMoved(ComponentEvent e) {}
            @Override
            public void componentShown(ComponentEvent e) {
                System.out.println("component shown");
            }
            @Override
            public void componentHidden(ComponentEvent e) {}
        }
                );
        popupMenu.add(menuItem);
        panel.setComponentPopupMenu(popupMenu);
        //========================================
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

共有2个答案

邵华皓
2023-03-14

我不认为您会发现某种侦听器会在显示JMenuItem时收到通知。

相反,我会尝试将JMenuItem从应用程序的状态中解耦,我会使用javax.swing.AbstractAction

当应用程序的上下文和/或状态发生变化时,您可以随时更新AbstractAction,当显示JMenuItem时,它将神奇地反映应用程序的上下文和状态。

下面的代码片段替换了jpopmpmenuJMenuItem的创建。第二部分展示了如何通过将JMenuItem转换为时钟来更新AbstractAction

    //========================================
    JPopupMenu popupMenu = new JPopupMenu();
    AbstractAction a = new AbstractAction("Reply Hi") {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Hi");
        }
    };
    JMenuItem menuItem = new JMenuItem(a);
    popupMenu.add(menuItem);
    panel.setComponentPopupMenu(popupMenu);
    //========================================
    Timer t = new Timer(100, (e) -> {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("'Its 'HH:mm:ss");
        a.putValue(Action.NAME, dtf.format(LocalTime.now()));
    });
    t.start();
    //========================================
赵嘉纳
2023-03-14

您可以使用一个AncestorListener

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

public class JMenuItemListeners {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        frame.setMinimumSize(new Dimension(800, 600));
        panel.setLayout(new BorderLayout());
        panel.add(new JLabel("Hello World... right click me."),
                BorderLayout.CENTER);
        //========================================
        JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem menuItem = new JMenuItem("Reply Hi");

        menuItem.addAncestorListener(new AncestorListener()
        {
            @Override
            public void ancestorRemoved(AncestorEvent e) {}
            @Override
            public void ancestorMoved(AncestorEvent e) {}
            @Override
            public void ancestorAdded(AncestorEvent e) {
                System.out.println("ancestor shown");
            }
        });

        popupMenu.add(menuItem);
        panel.setComponentPopupMenu(popupMenu);
        //========================================
        frame.setContentPane(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}
 类似资料:
  • vue3怎么封装一个显示代码的组件?

  • 我试图在一个Jasper报告中显示多个表,我使用子报告来实现这个功能。但我一直在显示几个子报告。实际上,只显示其中一个(第一个)。 以下是我的主report.jrxml: 下面是subjectSubreport.jrxml: 这是printersSubreport.jrxml: 当我切换子报告时,第一个报告正确显示,另一个报告消失。在JasperSoft Studio中,一切都很好,当我将它们导出

  • 用vscde在html文件中写Tailwind CSS,已经安装了Tailwind CSS IntelliSense插件,可以正常自动提示css语法。如下图所示: 但是在react组件中写Tailwind CSS时,不会像上面那样提示css语法。要怎样才可以让它显示提示?

  • 问题内容: 我正在尝试在上显示图像。我正在使用渲染图像,并且图像与类文件位于同一目录中。但是,没有显示图像,并且没有发生错误。谁能帮忙弄清楚我的代码有什么问题… 问题答案: 你应该用

  • 您可以在整个web上读到AWT是旧的和不推荐的,而Swing是旧的,但比AWT新,应该尽可能优先于AWT。但是我如何确定什么时候可以用它的摆动挂件替换AWT组件呢?web中的几个示例仍然使用AWT组件,其中可以使用Swing。那么有没有一个明确的建议,从AWT中使用什么,什么不使用?我知道,当我使用官方不推荐的组件时,java编译器会给出一个简短的说明,例如: 将产生如下警告: 换句话说:及其子包

  • 我使用fiddler监控一个简单的html内容从一个PHP文件运行在localhost。但是每当我按f5刷新页面(浏览器)时,在fiddler中有时整个web会话的字体变成蓝色,即当它实际显示内容(html)时,相反的情况发生在web会话是灰色的时候,它不显示html内容。 注意:始终显示请求/响应标题,这仅用于内容。我还尝试了点技巧(“:80”)并从localhost切换到127.0。0.1.