【问题标题】:Add JMenuItem to Already Visible JMenu将 JMenuItem 添加到已经可见的 JMenu
【发布时间】:2015-12-04 19:02:52
【问题描述】:

我已经在收听MenuListener.menuSelected() 以了解JMenu 何时出现在屏幕上。最初,JMenu 有 1 个JMenuItem,上面写着“正在加载...”。经过缓慢的操作,我将JMenuItems 添加到JMenuJMenu 继续显示“正在加载...”。如果我选择另一个JMenu 并返回,那么JMenu 会显示添加的JMenuItems。如何使添加的JMenuItems 立即显示?

这是重现正在发生的事情的代码。

public class AddMenuItem extends JFrame
{
   private final JMenu m_menu = new JMenu("Edit");

   public static void main(String args[])
   {
      new AddMenuItem().
         setVisible(true);
   }

   public AddMenuItem()
   {
      JMenuBar bar;

      bar = new JMenuBar();

      bar.add(m_menu);
      setJMenuBar(bar);
      setSize(600, 400);

      m_menu.addMenuListener(new MenuListener()
      {
         @Override
         public void menuSelected(MenuEvent e)
         {
            JMenuItem loading;

            loading = new JMenuItem("Loading...");

            loading.setEnabled(false);
            m_menu.removeAll();
            m_menu.add(loading);

            // This represents a long running task which updates the menu afterwards
            new Timer(5 * 1000, event -> updateMenu()).start();
         }

         @Override
         public void menuDeselected(MenuEvent e)
         {
            // nothing to do
         }

         @Override
         public void menuCanceled(MenuEvent e)
         {
            // nothing to do
         }
      });
   }

   private void updateMenu()
   {
      m_menu.removeAll();
      m_menu.add(new JMenuItem("1"));
      m_menu.add(new JMenuItem("2"));
      m_menu.add(new JMenuItem("3"));
      m_menu.revalidate();
   }
}

似乎这个code example 完全符合我的要求,但我不确定他们在做什么来使屏幕上的可见菜单重绘。

【问题讨论】:

    标签: java swing jmenu jmenuitem


    【解决方案1】:

    最初,JMenu 有 1 个 JMenuItem,上面写着“正在加载...”。

    从侦听器调用的代码在Event Dispatch Thread (EDT) 上执行。当您执行长时间运行的任务时,它会阻止 EDT 响应事件并重新绘制 GUI。

    因此,要解决由该菜单项启动的任务需要在单独的线程中执行的问题。您可能要考虑使用SwingWorker。阅读 Concurrency 上的 Swing 教程部分,了解有关 EDTSwingWorker 的更多信息。

    编辑:

    问题是,一旦我知道要向菜单添加什么,我就不知道如何让菜单显示添加的 JMenuItems

    您从MenuListenerMenuEvent 获得JMenu

    JMenu menu = (JMenu)e.getSource();
    menu.add( new JMenuItem( "Loading..." ) );
    

    编辑:

    基于 SSCCE,您可以执行以下操作:

       private void updateMenu()
       {
          m_menu.removeAll();
          m_menu.add(new JMenuItem("1"));
          m_menu.add(new JMenuItem("2"));
          m_menu.add(new JMenuItem("3"));
          JPopupMenu popup = m_menu.getPopupMenu();
          popup.pack();
       }
    

    但请记住,因为您的长时间运行任务在单独的线程中执行,您需要使用 SwingUtiltities.invokeLater 调用上述代码,以便在 EDT 上执行代码。

    似乎这个代码示例完全符合我的要求,但我不确定他们在做什么来使屏幕上的可见菜单重绘。

    我认为他们只是再次隐藏和显示菜单。

    【讨论】:

      【解决方案2】:

      不要执行m_menu.revalidate(),而是执行以下操作...

      if (m_menu.isPopupMenuVisible())
      {
         m_menu.setPopupMenuVisible(false);
         m_menu.setPopupMenuVisible(true);
      }
      

      【讨论】:

      • @camickr 的解决方案更好,因为它不允许弹出菜单的任何闪烁。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-30
      • 1970-01-01
      • 1970-01-01
      • 2012-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多