Crear barra de menu para nuestra aplicacion java

De ChuWiki

Vamos a crear una barra de menú para nuestra aplicación Java con varias opciones. Veremos algunos de las cosas habituales que se suelen querer en los menús. Puedes ver el ejemplo completo en JMenuExample.java

Creación del JMenuBar en nuestro JFrame[editar]

El JFrame de java, que suele ser la ventana principal de la aplicación, tiene ya preparado un método para añadirle un menú de opciones, el método setJMenuBar(). Hay otro método más antiguo, setMenuBar() sin la J, pero eso, es más antiguo.

Para añadir un menú con distintas opciones, tenemos varios componentes implicados:

  • JMenuBar: Es la barra principal del menú. A él añadiremos los menús desplegables hacia abajo con las distintas opciones.
  • JMenu: Es cada uno de los menús desplegables hacia abajo. Cada JMenu que añadamos al JMenuBar será un menú nuevo desplegable hacia abajo. Los típicos que aparecen en las aplicaciones como "File", "Edit", "View", etc.
  • JMenuItem. Este es cada una de los items o acciones en los que podemos hacer click en el menú para que se haga alguna de las opciones de nuestro menú. Por ejemplo, salvar un fichero, cerrar la aplicación, etc.
  • JSeparator. Para organizar los items de nuestros menús podemos poner separadores entre ellos, una línea horizontal.

La siguiente imagen muestra todo esto con un poco más de detalle, usando por ejemplo, un menú del entorno de desarrollo IntelliJ IDEA

El JMenuBar es la barra horizontal en rojo con las opciones File, Edit, View...

Los JMenu abren menús con opciones, he marcado algunos en verde. File por ejemplo es un JMenu y por eso abre el desplegable verde grande. Dentro hay otros JMenu, que aparecen con una > en el lado derecho, indicando de esta forma que se abren más opciones de menú. File properties en la imagen es un ejemplo.

Los JMenuItem son las acciones a ejecutar. No abren más menús y no salen con el símbolo > a la derecha. Restart IDE ... es un ejemplo.

Los JSeparator son esas líneas grises tenues que ves que separan opciones de menú. Por ejemplo, entre Close project y Settings hay una.

Darle funcionalidad a los JMenuItem[editar]

Antes de liarnos a construir los menús, vamos a ver como dar funcionalidad a un JMenuItem. Solo lo vamos a hacer con uno explicando los detalles de interés. El resto habría que ir haciéndolos de forma similar de uno en uno.

Para dar funcionalidad a cualquier tipo de botón en java y en concreto hay que meterle una clase que implemente ActionListener. Esta clase llava en su método actionPerformed la acción a ejecutar. Hay varias formas de crear esta clase que implemente Action y te comento por encima:

  • La clase que construye los menús, botones, etc, implementa ActionListener y se añade esta misma clase a todos los botones que crea. El método actionPerformed() tiene que mirar qué botón es el que se ha pulsado y ejecutar la acción que corresponda a esa botón. El texto, icono, tooltip etc que va en cada botón lo tiene que añadir este clase principal.
  • Construir una clase que implemente Action por cada acción. Esta clase lleva el método actionPerformed() con el código a ejecutar cuando se pulse el botón, pero también lleva el texto, icono, tooltip, tecla aceleradora etc. Como además haríamos una clase por cada opción de menú, no tiene que ver qué opción ejecutar.

¿Pegas e inconvenientes?. La segunda forma es más elegante, pero más engorrosa. La principal ventaja de esta segunda opción es que puedes reaprovechar esta Action en varios sitios, por ejemplo, imagina que además del menú principal con la opción "salvar fichero" tienes un JToolBar con el típico botoncito de disquete para salvar fichero. Puedes usar la misma Action en ambos sitios, en el JMenuItem y en el JToolBar

Aquí vamos en el ejemplo con la segunda forma. Vamos con el ejemplo de salvar fichero. El código para crear esa Action puede ser el siguiente

        Action saveAction = new AbstractAction("Save") {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Save clicked");
            }
        };
        saveAction.putValue(Action.ACCELERATOR_KEY,KeyStroke.getKeyStroke(KeyEvent.VK_S,ActionEvent.ALT_MASK));
        saveAction.putValue(Action.SHORT_DESCRIPTION,"Save the file");
        saveAction.putValue(Action.SMALL_ICON,new ImageIcon("src/main/files/Actions-document-save-icon.png"));

Vamos a explicarlo un poco.

Creamos una Action de nombre "saveAction" instanciando una clase AbstractAction. Es una forma de ahorrarnos escribir mucho código, ya que AbstractAction tiene código ya implementado que no tiene Action.

En el constructor podemos pasar como parámetro "Save" que sería el texto que queremos que aparezca visible en la opción del menú. Al instanciar AbstractAction nos obliga a implementar el método actionPerformed(), que es donde debemos meter el código de salvar fichero. Por no liarlo mucho, aquí simplemente he puesto un System.out.println() para que salga algo por pantalla y así saber que el código se ha enterado de que se ha pulsado el botón.

Y después llega el momento de liarse a ponerle "cosas" a nuestra opción de menú. Estas cosas se ponen llamando al método putValue() que admite dos parámetros. Un identificador para saber qué estamos cambiando y el valor que queremos poner. Hay muchos posibles identificadores, pero estos de aquí son los más típicos:

  • ACCELERATOR_KEY: Combinación de teclas para ejecutar la acción del menú sin necesidad de ir con el ratón, también llamados atajos de teclado. La clave es Action.ACCELERATOR_KEY y el valor es el KeyStroke concreto que represente nuestra combinación de teclas. Queremos en este ejemplo que sea Alt-S. Así que llamamos a KeyStroke.getKeyStroke() y le pasamos dos parámetros:
    • La tecla en concreto, que es KeyEvent.VK_S. La "S" del final es la que nos da la clave. KeyEvent tiene constantes definidas para todas las teclas posibles de un teclado, incluyendo teclas "raras" como F1, F2, ESC, etc.
    • El modificador para la tecla, es decir, si se debe pulsar simultáneamente con Ctrl, Alt, Shift, etc. ActionEvent tiene estos modificadores y como en este ejemplo queremos que sea Alt, ponemos ActionEvent.ALT_MASK. Tienes bastantes más modificadores.
  • SHORT_DESCRIPTION: El tooltip de la opción de menú. El tooltip es un pequeño texto que sale cuando dejamos el ratón encima de la opción de menú, pero sin hacer click. Este texto suele describir brevemente qué hace dicha opción de menú.
  • SMALL_ICON: Un icono para la opción de menú. La forma fácil de crearlo es instanciar un ImageIcon pasándole el fichero que tiene el icono.

La siguiente imagen muestra como quedaría esta acción una vez hayamos construido el JFrame con su JMenuBar y sus JMenuItem

Vemos que la opción "Save" tiene un icono y aparece el atajo de teclado "Alt-S". También se ve el tooltip.

Construir el menú[editar]

Básicamente debemos instanciar una clase JMenuBar, que será la barra de menú que podemos añadir a nuestra ventana.

 JMenuBar jMenuBar = new JMenuBar();

Luego, a esta barra de menú debemos añadirle los JMenu que queramos. En nuestro ejemplo solo vamos a añadir dos, uno para File y otro para "Help". Pero con una particularidad. Si vamos añadiendo los JMenu sin más, se irán colocando consecutivamente de izquierda a derecha, pegados al lado izquierdo. Queremos que nuestro menú "Help" esté al lado derecho. Para ello, justo antes de añadir el JMenu "Help", debemos añadir un componente swing especial, el "HorizontalGlue". Es simplemente un componente que rellena todo el hueco antes de "Help" para hacer que "Help se desplace a la derecha.

        // Añadimos JMenu File
        JMenu fileMenu = new JMenu("File");
        jMenuBar.add(fileMenu);

        // Podriamos añadir otros JMenu con otras opciones, como Edit, View, etc.

        // Añadimos el separador para obligar al resto de JMenu que añadamos a pegarse al lado derecho.
        jMenuBar.add(Box.createHorizontalGlue());

        // Añadimos el JMenu Help que se irá a la derecha del todo.
        JMenu aboutMenu = new JMenu("Help");
        jMenuBar.add(aboutMenu);

Listo, el "Horizontal Glue" lo hemos creado llamando a Box.createHorizontalGlue()

y ahora tenemos que añadir a cada JMenu sus JMenuItem con sus JSeparator si los queremos o incluso con otros JMenu para hacer un anidamiento más de submenús, los que en la primera foto dijimos que tenían una > en el lado derecho.

        // Para el JMenu File pondemos dos acciones: Save y Save As.
        JMenuItem saveItem = new JMenuItem(saveAction);
        JMenuItem saveAsItem = new JMenuItem("Save As");
        fileMenu.add(saveItem);
        fileMenu.add(saveAsItem);

        // Le añadimos un separador
        fileMenu.add(new JSeparator());

        // Y ponemos una opción Exit
        JMenuItem exitItem = new JMenuItem("Exit");
        fileMenu.add(exitItem);

        // En cuanto al JMenu Help, le añadimos una opción About.
        JMenuItem about = new JMenuItem("About");
        aboutMenu.add(about);

Solo unos detalles.

Para el JMenuItem de Save habíamos creado una Action y la habíamos llamado "saveAction". Esa la pasamos directamente en el constructor de JMenuItem. Eso ya deja esta opción de menú totalmente configurada con su acción a ejecutar, icono, atajo de teclado, tooltip y texto visible.

Para los demás JMenuItem como no creamos acciones por no embarullar el código, solamente ponemos en el constructor el nombre visible. Así cuando arranquemos la aplicación veremos todas las opciones de menú con su nombre, pero no harán nada, ni tendrán icono, ni tooltip ni atajo de teclado. Tendrías que crear Action para cada una de ellas y pasarla en el constructor.

Hemos puesto un JSeparator dentro del menú File, para separar "Save" y "Save As" de "Exit".

Añadir el menú a la ventana[editar]

Con esto queda listo nuestro menú, sólo hay que añadirlo a nuestra ventana. Los JFrame tiene un método específico para eso

frame.setJMenuBar(jMenuBar);