2015-12-04 8 views
1

Я уже слушаю MenuListener.menuSelected(), чтобы узнать, когда на экране отображается JMenu. Первоначально JMenu имеет 1 JMenuItem, в котором говорится: «Загрузка ...». После медленной операции я добавляю JMenuItem s к JMenu. JMenu продолжает показывать «Загрузка ...». Если я выберу еще JMenu и вернусь, тогда JMenu покажет добавленные JMenuItem s. Как я могу добавить добавленные JMenuItem s для немедленного отображения?Добавить JMenuItem в уже видимый JMenu

Вот код, который воспроизводит то, что происходит.

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 делает именно то, что я хочу, но я не уверен, что они делают, чтобы сделать видимым меню перекрашивать на экране.

ответ

3

Первоначально JMenu имеет 1 JMenuItem, в котором говорится: «Загрузка ...».

Код, вызываемый слушателем, выполняется на Event Dispatch Thread (EDT). Когда вы выполняете долговременную задачу, она не позволяет EDT отвечать на события и перерисовывать графический интерфейс.

Чтобы решить проблему, задача, начатая этими пунктами меню, должна выполняться в отдельном потоке. Возможно, вы захотите рассмотреть возможность использования SwingWorker. Прочтите раздел из руководства Swing по телефону Concurrency для получения дополнительной информации о EDT и SwingWorker.

Edit:

Проблема заключается в том, что когда-то я знаю, что добавить в меню, я не знаю, как получить меню, чтобы показать добавленные JMenuItems

Вы получаете JMenu от MenuEvent из ваших MenuListener:

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

Edit:

На основе 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.

Кажется, что этот пример кода делает именно то, что я хочу, но я не уверен, что они делают, чтобы визуальное меню перерисовывалось на экране.

Я думаю, что они просто скрываются и снова показывают меню.

0

Вместо того чтобы делать m_menu.revalidate(), сделайте следующее ...

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

решения @camickr «ы лучше, так как он не позволяет для любого мерцания всплывающего меню. – Nathan