2009-12-14 39 views
8

He creado un menú desplegable en mi Swing JToolBar. Pero no crea comportarse de la manera que quiero. Mi objetivo es que funcione como el botón "Marcadores Inteligentes" de Firefox.¿Cómo puedo crear un menú "desplegable" en una barra de herramientas Java Swing?

Desaparece cuando el usuario selecciona un elemento de menú: ¡CORRECTO!

Desaparece cuando el usuario presiona ESC: ¡CORRECTO!

Desaparece cuando el usuario hace clic en algún lugar en el marco principal fuera del menú: ¡CORRECTO!

Pero no desaparece cuando el usuario hace clic una segunda vez en el botón que muestra el menú desplegable: INCORRECTO ... :-(

Mi pregunta es ¿cómo puedo agregar este comportamiento, que que no desaparecen cuando los clics en el botón que muestra el menú una segunda vez

Aquí está mi código actual, desde Java 6 en el 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()); 
    } 
} 

Respuesta

4

Bueno, aquí hay una solución potencial que no está exenta de inconvenientes. Solo usted puede decidir si esto es aceptable para su aplicación. El problema es que el cierre emergente ocurre antes de que se activen otros eventos de manejo del mouse, por lo que al hacer clic en el botón Más ... se oculta la ventana emergente, reseteando el estado de los botones ANULAR antes de que se oiga el botón.

La solución fácil es añadir la siguiente llamada dentro de su programa principal:

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

El resultado de esto es que cada vez que un menú emergente se cierra debido a un evento del ratón pulsado, ese evento ratón será consumido en el momento en que se cierra el menú y no se transferirá a ningún otro componente con el mouse. Si puedes vivir con limitaciones, esta es una solución fácil.

+0

Funciona como un encanto ... Una pregunta: ¿cómo se enteró de esta solución? Está documentado en alguna parte? –

+1

En realidad, solo estaba usando mi depurador (con el src JDK adjunto) para averiguar dónde y cuándo se activaban los eventos. Lo encontré en BasicPopupMenuUI. – BryanD

-1

Bueno, el oyente en el botón reacciona sólo cuando es empujado hacia abajo, porque escuchas por ItemEvent.SELECTED eventos solamente ¿Qué tal si la adición de otra cláusula para escuchar ItemEvent.DESELECTED eventos aquí:

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

Usted podría almacenar una referencia a la menu en alguna parte, o que podría hacer que el menú en sí añadir otro oyente al botón. La última solución podría ser más sencilla, ya que parece que envía una referencia de botón al menú.

+0

Joonas, ¿ha intentado su sugerencia? Lo intenté y parece que no funciona. El menú emergente activa un evento de cancelación al hacer clic en el botón, que desmarca el botón. Esto asegura que el botón esté siempre configurado para seleccionar cuando hace clic en él. –

+0

No he probado exactamente el código anterior, pero estoy bastante seguro de que debería funcionar de la manera que describo. Tal vez no entiendo algo, pero dependiendo del evento popupMenuCanceled() parece frágil, ya que la documentación solo dice que "se llama a este método cuando se cancela el menú emergente". ¿Que se supone que significa eso? Sugiero simplemente agregar un oyente explícito para el estado del botón. –

+0

Joonas, el problema es que su sugerencia simplemente no funciona. Pruébalo y mira. –

0

No uso Firefox, así que no sé cómo se ve el botón Marcadores inteligentes, pero tal vez use un JMenu como el "botón". Podría intentar usar el borde de un JButton para que se parezca más a un botón.

+0

Esto debería hacer el truco – willcodejavaforfood

+0

Intenté esto, no es un buen resultado. –

+0

Así que abajo vota la sugerencia porque no se parece a lo que quieres. Es bueno saber que la próxima vez que trabaje le daré un tipo de sugerencia "fuera de la caja". Lo tengo funcionando así que no sé qué problemas tienes. – camickr

1

Lo que sucede es que cuando hace clic en el menú, cancela el menú emergente, por lo que deselecciona el botón, pero el siguiente evento inmediato es hacer clic en el botón y ahora se desactiva para mostrar el menú nuevamente.

no tengo la solución exacta todavía, pero dame un poco ...

Cuestiones relacionadas