## Cómo Utilizar Menús

Un menú proporciona una forma de ahorrar espacio y permitir al usuario elegir una entre varias opciones. Otros componentes con los que el usuario puede hacer una elección incluyen combo boxes, lists, radio buttons, y tool bars. Si alguno de los ítems de un menú realiza una acción que está duplicada en otro ítem de menú o en un botón de una barra de herramientas, además de esta lección deberíamos leer Como usar Actions.

Los menús son únicos en que, por convención, no se sitúan con los otros componentes en el UI. En su lugar, aparecen en una barra de menú o en un menú desplegable. Una barra de menú contiene uno o más menús, y tiene una posición dependiente de la plataforma -- normalmente debajo de la parte superior de la ventana. Un menú desplegable es un menú que es invisible hasta que el usuario hace una acción del ratón específica de la plataforma, como pulsar el botón derecho del ratón sobre un componente. Entonces el menú desplegable aparece bajo el cursor.

La siguiente figura muestra los componentes Swing que implementan cada parte de un sistema de menús.

El resto de esta sección nos enseña los componentes de menú y nos dice cómo utilizar varias de sus características:

- La herencia de componentes menú
- Crear menús
- Manejar Eventos desde ítems de menú
- Traer un Menú desplegable
- Personalizar un Menú
- El API Menu
- Ejemplos que utilizan Menús

#### La herencia de componentes Menú

> Aquí podemos ver el árbol de herencia de las clases relacionadas con los menús:

> Como se ve en la figura, los ítems de menús (incluidos los propios menús) son simples botones. Podríamos preguntarnos como un menú, si es sólo un botón, muestra sus ítems. La respuesta es que cuando se activa un menú, automáticamente trae un menú desplegable que muestra sus ítems.

#### Crear Menús

> Aquí está el código que crea los menús mostrados al principio de esta página. Puedes encontrar el programa completo en MenuLookDemo.java. Para ejecutarlo, necesitas tener el fichero de imagen: images/middle.gif. Como este código no tiene manejo de eventos, los menús no hacen nada útil, excepto verse como serían. Si ejecutamos el ejemplo, observaremos que a pesar de no tener un manejo de eventos, los menús y submenús aparecen cuando deben, y los checkbox y los botones de radio responden apropiadamente cuando el usuario los elige.

>     //in the constructor for a JFrame subclass:
>     JMenuBar menuBar;
>     JMenu menu, submenu;
>     JMenuItem menuItem;
>     JCheckBoxMenuItem cbMenuItem;
>     JRadioButtonMenuItem rbMenuItem;
>     ...
>     //Create the menu bar.
>     menuBar = new JMenuBar();
>     setJMenuBar(menuBar);

>     //Build the first menu.
>     menu = new JMenu("A Menu");
>     menuBar.add(menu);

>     //a group of JMenuItems
>     menuItem = new JMenuItem("A text-only menu item");
>     menu.add(menuItem);
>     menuItem = new JMenuItem("Both text and icon",
>     new ImageIcon("images/middle.gif"));
>     menu.add(menuItem);
>     menuItem = new JMenuItem(new ImageIcon("images/middle.gif"));
>     menu.add(menuItem);

>     //a group of radio button menu items
>     menu.addSeparator();
>     ButtonGroup group = new ButtonGroup();
>     rbMenuItem = new JRadioButtonMenuItem("A radio button menu item");
>     rbMenuItem.setSelected(true);
>     group.add(rbMenuItem);
>     menu.add(rbMenuItem);
>     rbMenuItem = new JRadioButtonMenuItem("Another one");
>     group.add(rbMenuItem);
>     menu.add(rbMenuItem);

>     //a group of check box menu items
>     menu.addSeparator();
>     cbMenuItem = new JCheckBoxMenuItem("A check box menu item");
>     menu.add(cbMenuItem);
>     cbMenuItem = new JCheckBoxMenuItem("Another one");
>     menu.add(cbMenuItem);

>     //a submenu
>     menu.addSeparator();
>     submenu = new JMenu("A submenu");
>     menuItem = new JMenuItem("An item in the submenu");
>     submenu.add(menuItem);
>     menuItem = new JMenuItem("Another item");
>     submenu.add(menuItem);
>     menu.add(submenu);

>     //Build second menu in the menu bar.
>     menu = new JMenu("Another Menu");
>     menuBar.add(menu);

> Como se ve en el código, para configurar una barra de menú para un JFrame, se utiliza el método setJMenuBar. Para añadir un JMenu a un JMenuBar, se utiliza el método add(JMenu). Para añadir ítems de menú y submenús a un JMenu, se utiliza el método add(JMenuItem). Estos métodos y otros más se listan en El API de JMenu.

#### Manejar Eventos desde Ítems de Menús

> Para detectar cuando el usuario selecciona un JMenuItem, se puede escuchar por eventos action (igual que se haría para un JButton). Para detectar cuando el usuario selecciona un JRadioButtonMenuItem, se puede escuchar tanto por eventos action, como por eventos item, como se describio en Cómo usar Radio Buttons. Para JCheckBoxMenuItems, generalmente se escuchan eventos de item, como se describió en Cómo usar CheckBox.

> La siguiente figura muestra un programa que añade detección de eventos al ejemplo anterior. El código del programa está en MenuDemo.java. Al igual que MenuLookDemo, MenuDemo utiliza el fichero de imagen images/middle.gif.

> Aquí está el código que implementa el manejo de eventos:

>     public class MenuDemo ... implements ActionListener, ItemListener {
>         ...
>         public MenuDemo() {
>             ...//for each JMenuItem instance:
>             menuItem.addActionListener(this);

>             ...//for each JRadioButtonMenuItem:
>             rbMenuItem.addActionListener(this);

>             ...//for each JCheckBoxMenuItem:
>             cbMenuItem.addItemListener(this);
>             ...
>         }

>         public void actionPerformed(ActionEvent e) {
>             ...//Get information from the action event...
>             ...//Display it in the text area...
>         }

>         public void itemStateChanged(ItemEvent e) {
>             ...//Get information from the item event...
>             ...//Display it in the text area...
>         }

> Para ejemplos de manejo de eventos action e item, puedes ver las páginas, button, radio button, y check box, así como la lista de ejemplos al final de esta página

#### Traer un Menú Desplegable

> Para traer un menú desplegable (JPopupMenu), debemos registrar un oyente de ratón para cada componente al que debería estar asociado el menú desplegable. El oyente de mouse debe detectar las peticiones del usuario para que aparezca el menú desplegable. Para las plataformas Windows y Motif, el usuario trae un menú desplegable pulsando el botón derecho del ratón mientras el cursor está sobre el coponente adecuado.

> El oyente de mouse trae un menú desplegable llamando a setVisible(true) sobre el ejemplar apropiado de JPopupMenu. El siguiente código, tomado de PopupMenuDemo.java, muestra cómo crear y mostrar menús desplegables:

>     ...//where instance variables are declared:
>     JPopupMenu popup;

>         ...//where the GUI is constructed:
>         //Create the popup menu.
>         popup = new JPopupMenu();
>         menuItem = new JMenuItem("A popup menu item");
>         menuItem.addActionListener(this);
>         popup.add(menuItem);
>         menuItem = new JMenuItem("Another popup menu item");
>         menuItem.addActionListener(this);
>         popup.add(menuItem);

>         //Add listener to components that can bring up popup menus.
>         MouseListener popupListener = new PopupListener();
>         output.addMouseListener(popupListener);
>         menuBar.addMouseListener(popupListener);
>     ...
>     class PopupListener extends MouseAdapter {
>         public void mousePressed(MouseEvent e) {
>             maybeShowPopup(e);
>         }

>         public void mouseReleased(MouseEvent e) {
>             maybeShowPopup(e);
>         }

>         private void maybeShowPopup(MouseEvent e) {
>             if (e.isPopupTrigger()) {
>                 popup.show(e.getComponent(),
>                            e.getX(), e.getY());
>             }
>         }
>     }

Los menús desplegables tienen unos pocos detalles interesantes de implementación. Uno es que cada menú tiene un menú desplegable apropiado. Cuando el menú se activa, utiliza su menú desplegable para mostrar sus ítems de menú.

Otro detalle es que un propio menú desplegable utiliza otro componente para implementar la ventana que contiene los ítems del menú. Dependiendo de las circunstancias bajo las que se muestre el menú desplegable, podría implementar su "ventana" utilizando un componente de peso ligero (como un JPanel), un componente de peso medio (como un Panel), o una ventana de peso pesado (Window).

Las ventanas desplegables de peso ligero son más eficientes que las ventanas de peso pesado, pero no funcionan bien si tenemos componentes pesados dentro de nuestro GUI. Especificamente, cuando un área de una ventana desplegable de peso ligero se intersecciona con un componente de peso pesado, el componente de peso pesado se dibuja encima. Esta es una de las razones porla que recomendamos no mezclar componentes de peso ligero y de peso pesado. Si realmente necesitamos utilizar un componente de peso pesado en nuestro GUI, podemos utilizar el método setLightWeightPopupEnabled de JPopupMenu para desactivar las ventanas desplegables de peso ligero. Para más detalles puedes ver el artículo Mezclar componentes de peso ligero y pesado, de La conexión Swing. (En inglés).

#### Personalizar la Distribución de un Menú

> Como los menús se hacen con componentes ordinarios Swing, podemos personalizarlos fácilmente. Por ejemplo, podemos aañadir cualquier componente de peso ligero a un JMenu o JMenuBar. Y como JMenuBar utiliza BoxLayout, podemos personalizar la distribución de la barra de menú añadiéndole componentes invisibles. Aquí tienes un ejemplo que añade un componente glue a una barra de menú, para que el último elemento del menú se sitúe en el lado derecho de la barra de menú:

>     ...//create and add some menus...
>     menuBar.add(Box.createHorizontalGlue());
>     ...//create the LEFTmost menu...
>     menuBar.add(LEFTMenu);

> Aquí podemos ver una imagen del resultado, que podemos duplicar compilando y ejecutando MenuGlueDemo.java:

> Otra forma de cambiar el aspecto de un menú es cambiar el controlador de distribución que lo controla. Por ejemplo, podemos cambiar el controlador de distribución de la barra de menú del valor por defecto BoxLayout de izquierda-derecha, a algo como un GridLayout. También podemos cambiar como un menú activado u otro menú desplegable distribuye sus ítems, como demuestra MenuLayoutDemo.java. Aquí podmeos ver una imagen de la distribución de menús que crea MenuLayoutDemo:

#### El API de JMenu

> Las siguientes tablas listan los métodos y constructores más utilizados de Jmenu. El API se divide en estas categorías:
> - Crear y Configurar Barras de Menú
> - Crear y Rellenar Menús
> - Crear, Rellenar y Controlar Menús Desplegables
> - Implementar Ítems de Menú

> Crear y Configurar Barras de Menú
> Método | Propósito
> --- | ---
> JMenuBar() | Crea una barra de menú.
> void setJMenuBar(JMenuBar) JMenuBar getJMenuBar() (en JApplet, JDialog, JFrame, JRootPane) | Selecciona u obtiene la barra de menú de un applet, dialog, frame, o root pane. En las siguientes versiones de Swing y del JDK 1.2, los frames internos también soportarán estos métodos.
> void setMenuBar(JMenuBar) JMenuBar getMenuBar() (en JInternalFrame) | Selecciona u obtiene la barra de menú de un Frame interno. En las siguientes versiones de Swing y del JDK 1.2, este método será anulado y deberíamos utilizar setJMenuBar/getJMenuBar.

> Crear y Rellenar Menús
> Método | Propósito
> --- | ---
> JMenu() | Crea un menú.
> JMenuItem add(JMenuItem) JMenuItem add(Action) void add(String) | Añade un ítem de menú al final del menú. Si el argumento es un objeto Action, el menú crea un ítem de menú como se describe en Cómo usar Actions. Si el argumento es un string, el menú crea automáticamente un objeto JMenuItem que muestra el texto especificado.
> void addSeparator() | Añade un separador la final del menú.
> >JMenuItem insert(JMenuItem, int) JMenuItem insert(Action, int) void insert(String, int) void insertSeparator(int) | Inserta un ítem de menú o un separador en un menú, en la posición especificada. El primer ítem de menú es la posición 0, el segundo la posición 1, etc. Los argumentos JMenuItem, Action, y String se tratan de la misma forma que en los correspondientes métodos add.
> void remove(JMenuItem) void remove(int) void removeAll() | Elimina el ítem o ítems especificados del menú. Si el argumento es un entero, especifica la posición del ítem a eliminar.

> Crear y Rellenar Menús Desplegables
> Método | Propósito
> --- | ---
> JPopupMenu() JPopupMenu(String) | Crea un menú desplegable. El argumento string opcional especifica el título que el aspecto y comportamiento podría mostrar como parte de la ventana desplegable.
> JMenuItem add(JMenuItem) JMenuItem add(Action) | Añade un ítem de menú al final del menú desplegable. Si el argumento es un objeto Action, el menú crea un ítem como se describe en Cómo usar Actions.
> void addSeparator() | Añade un separador al final del menú desplegable.
> void insert(Component, int) JMenuItem insert(Action, int) | Inserta un ítem de menú en la posición especificada. El primer ítem del menú está en la posición 0, el segundo en la posición 1, etc. El argumento Component específica el ítem de menú a añadir. El argumento Action es tratado de la misma forma que en el método add correspondiente.
> void remove(JMenuItem) void remove(int) void removeAll() | Elimina el ítem o ítems especificados del menú. Si el argumento es un entero, especifica la posición del elemento del menú a eliminar.
> static void setDefaultLightWeightPopupEnabled(boolean) | Por defecto, Swing implementa una ventana de menú utilizando un componente de peso ligero. Esto causa problemas su utilizamos componentes de peso pesado en nuestro programa Swing, como se describió en Traer un Menú Desplegable. Para evitar estos problemas, se puede llamar a JPopupMenu.setDefaultLightWeightPopupEnabled(false).
> void show(Component, int, int) | Muestra el menú desplegable en la posición X,Y (especificada en el orden de los argumentos enteros) en el sistema de coordenadas del componente especificado.

> Implementar Ítems de Menú
> Método | Propósito
> --- | ---
> JMenuItem() JMenuItem(Icon) JMenuItem(String) JMenuItem(String, Icon) JMenuItem(String, int) | Crea un ítem de menú normal. El argumento icon, si existe, especifica el icono que debería mostrar el ítem de menú. Igualmente el argumento String, especifica el texto que debería mostrar el ítem de menú. El argumento entero especifica el mnemónico de teclado a utilizar. Se puede especifar una de las constantes VK definidas en la clase KeyEvent. Por ejemplo, para especificar "a" como el mnemónico, podemos utilizar KeyEvent.VK_A.
> JCheckBoxMenuItem() JCheckBoxMenuItem(Icon) JCheckBoxMenuItem(String) JCheckBoxMenuItem(String, Icon) JCheckBoxMenuItem(String, boolean) JCheckBoxMenuItem(String, Icon, boolean) | Crea un ítem de menú que se parece y actúa como un checkbox. Si se especifica un icono, el ítem de menú utiliza el icono en vez del icono por defecto de los checkboxes. El argumento string, si existe, especifica el texto que debería mostrar el ítem de menú. Si se especifica true para el argumento booleano, el ítem de menú estará inicialmente seleccionado. De lo contario el íten de menú está desactivado.
> JRadioButtonMenuItem() JRadioButtonMenuItem(Icon) JRadioButtonMenuItem(String) JRadioButtonMenuItem(String, Icon)< | Crea un ítem de menú que se parece y actúa como un radio buttom. Si se especifica un icono, el ítem de menú utiliza el icono en vez del icono por defecto de los botones de radio. El argumento string, si existe, especifica el texto que debería mostrar el ítem de menú. El ítem de menú está inicialmente desactivado.
> void setState(boolean) boolean getState() | Seleciona u obtiene el estado de selección de un ítem de menú.
> void setEnabled(boolean) | Si el argumento es true, activa el ítem de menú, si es false lo desactiva.
> void setMnemonic(char) | Selecciona la tecla alternativa para seleccionar el ítem de menú sin el ratón.
> void setActionCommand(String) | Seleciona el nombre de la acción realizada por el ítem de menú.
> void addActionListener(ActionListener) void addItemListener(ItemListener) | Añade un oyente de eventos al ítem de menú. Puedes ver Manejar Eventos desde Ítems de Menús para más detalles.
> La mayoría de los métodos anteriores son heredados desde AbstractButton. Puedes ver El API Button para más información sobre otros métodos útiles proporcionados por AbstractButton.

#### Ejemplos que utilizan Menús

> Los Menús son utilizados en unos pocos ejemplos Swing.

> Ejemplo | Donde se Describe | Notas
> --- | --- | ---
> MenuLookDemo.java | Esta Página. | Un sencillo ejemplo que crea toda clase de menús, excepto desplegables, pero no maneja eventos.
> MenuDemo.java | Esta página | Añade manejo de eventos a MenuLookDemo.
> MenuGlueDemo.java | Esta página | Demuestra la distribución de menús añadiendo un componente invisible a la barra de menú.
> MenuLayoutDemo.java | Esta página | Implementa la apertura lateral de menús en una barra de menú vertical.
> ActionDemo.java | Cómo usar Actions | Utiliza objetos Action para implementar ítems de menú que duplican la funcionalidad proporcionada por una barra de botones.
> InternalFrameDemo.java | Cómo usar Frames Internos | Utiliza un ítem de menú para crear ventanas.

Ozito