2009-12-14 4 views
8

Я создал раскрывающееся меню на моем Swing JToolBar. Но он не создает поведения так, как я хочу. Я нацелен на то, чтобы он работал как кнопка «Умные закладки» Firefox.Как создать меню «Выпадающее меню» на панели инструментов Java Swing?

Он исчезает, когда пользователь выбирает пункт меню: CORRECT!

Он исчезает, когда пользователь нажимает ESC: CORRECT!

Он исчезает, когда пользователь щелкает где-то в главном кадре вне меню: CORRECT!

Но она не исчезает, когда пользователь щелкает второй раз на кнопку, которая показывает выпадающее меню: некорректное ... :-(

Мой вопрос, как я могу добавить такое поведение, что она исчезает, когда нажимает на кнопку, которая показывает меню во второй раз

Вот мой текущий код из Java 6 на Mac:.

import javax.swing.*; 
import javax.swing.event.PopupMenuEvent; 
import javax.swing.event.PopupMenuListener; 
import java.awt.*; 
import java.awt.event.ItemEvent; 
import java.awt.event.ItemListener; 

public class ScratchSpace { 

    public static void main(String[] arguments) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       JFrame frame = new JFrame("Toolbar with Popup Menu demo"); 

       final JToolBar toolBar = new JToolBar(); 
       toolBar.add(createMoreButton()); 

       final JPanel panel = new JPanel(new BorderLayout()); 
       panel.add(toolBar, BorderLayout.NORTH); 
       panel.setPreferredSize(new Dimension(600, 400)); 
       frame.getContentPane().add(panel); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    private static AbstractButton createMoreButton() { 
     final JToggleButton moreButton = new JToggleButton("More..."); 
     moreButton.addItemListener(new ItemListener() { 
      public void itemStateChanged(ItemEvent e) { 
       if (e.getStateChange() == ItemEvent.SELECTED) { 
        createAndShowMenu((JComponent) e.getSource(), moreButton); 
       } 
      } 
     }); 
     moreButton.setFocusable(false); 
     moreButton.setHorizontalTextPosition(SwingConstants.LEADING); 
     return moreButton; 
    } 

    private static void createAndShowMenu(final JComponent component, final AbstractButton moreButton) { 
     JPopupMenu menu = new JPopupMenu(); 
     menu.add(new JMenuItem("Black")); 
     menu.add(new JMenuItem("Red")); 

     menu.addPopupMenuListener(new PopupMenuListener() { 
      public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 
      } 

      public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 
       moreButton.setSelected(false); 
      } 

      public void popupMenuCanceled(PopupMenuEvent e) { 
       moreButton.setSelected(false); 
      } 
     }); 

     menu.show(component, 0, component.getHeight()); 
    } 
} 

ответ

4

Ну, вот потенциальное решение, которое не лишено недостатков. Только вы можете решить, приемлемо ли это для вашего приложения. Проблема в том, что всплывающее закрытие происходит до того, как будут запущены другие события обработки мыши, поэтому нажатие на кнопку More .. снова вызывает всплывающее окно, поэтому сброс состояния кнопок отменяется до того, как кнопка даже сообщит, что она нажата.

Простой обходной путь, чтобы добавить следующий вызов внутри основной программы:

UIManager.put("PopupMenu.consumeEventOnClose", Boolean.TRUE); 

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

+0

Работает как шарм ... Вопрос: как вы узнали об этом решении? Это где-то задокументировано? –

+1

На самом деле я просто использовал мой отладчик (с прикрепленным JDK src), чтобы узнать, где и когда были запущены события. Я нашел его в BasicPopupMenuUI. – BryanD

-1

Ну, слушатель на кнопку реагирует только тогда, когда он толкается, потому что вы слушаетеТолькособытий. Как насчет добавления другого, если положение для прослушивания ItemEvent.DESELECTED событий здесь:

moreButton.addItemListener(new ItemListener() { 
     public void itemStateChanged(ItemEvent e) { 
      if (e.getStateChange() == ItemEvent.SELECTED) { 
       createAndShowMenu((JComponent) e.getSource(), moreButton); 
      } 
     } 
    }); 

Вы можете либо сохранить ссылку на menu где-нибудь, или вы могли бы сделать само меню добавить еще один слушатель кнопку. Последнее решение может быть более простым, поскольку вы уже, похоже, отправляете ссылку на кнопку в меню.

+0

Йонас, вы пробовали свое предложение? Я пробовал это, и он, похоже, не работает. Всплывающее меню запускает событие отмены при нажатии кнопки, которая не выбирает кнопку. Это гарантирует, что кнопка всегда будет выбрана, когда вы нажмете на нее. –

+0

Я не тестировал точно код выше, но я уверен, что он должен работать так, как я описываю. Может быть, я что-то не понимаю, но в зависимости от popupMenuCanceled() событие кажется хрупким, поскольку в документации только говорится, что «Этот метод вызывается, когда всплывающее меню отменено». Что это должно означать? Я предлагаю просто добавить явный слушатель для состояния кнопки. –

+0

Joonas, проблема в том, что ваше предложение просто не работает. Попробуй и посмотри. –

0

Я не использую Firefox, поэтому я не знаю, как выглядит кнопка Smart Bookmarks, но, возможно, использовать JMenu как «кнопку». Вы можете попробовать использовать границу JButton, чтобы она выглядела больше как кнопка.

+0

Это должно сделать трюк – willcodejavaforfood

+0

Пробовал это, это не очень хороший результат. –

+0

Итак, вы голосуете за предложение, потому что оно не похоже на то, что вы хотите. Полезно знать, в следующий раз, когда я работаю, вы предлагаете тип предложения «вне коробки». У меня это работает, поэтому я не знаю, какие у вас проблемы. – camickr

1

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

У меня нет точного решения пока нет, но дайте мне немного ...

Смежные вопросы