Crear y operar con menús en Xojo

Una aplicación de escritorio, ya sea multiplataforma o no, ha de tener menús. Estos son los primeros elementos de interacción que espera cualquier usuario para navegar por entre las opciones ofrecidas por nuestros programas. De hecho, y más allá de las posibles opciones ofrecidas a través de los menús contextuales (de los que hablaré en otra ocasión), la primera toma de contacto de una amplia mayoría de usuarios pasa por recorrer las entradas en el menú de la aplicación para saber “dónde está cada cosa” y qué puede hacer.

Entre las múltiples virtudes de Xojo se encuentra la de contar en su IDE con un excelente soporte tanto para el diseño de los menús como para comprobar su visualización, aproximada, en las diferentes plataformas de escritorio soportadas: OS X, Windows y Linux (Windows y Linux son muy similares, realmente).

De hecho, cuando creamos una nueva aplicación de escritorio, Xojo ya se encuentra de proporcionar como parte del armazón de la aplicación un menún principal y que está asociado, también por omisión, a la ventana de aplicación creada como parte del proyecto.

Barra de menús por omisión en Xojo para Desktop

Evidentemente, y en función de las necesidades de nuestras aplicaciones, podremos crear nuevas barras de menús utilizando el botón Insert de la barra de herramientas o bien el menú Insert > Menú Bar.

Añadir nuevos elementos a la Barra de Menús

Para acceder al Editor de Menús, sólo es preciso seleccionar la entrada correspondiente al menú en la Área de Navegación del proyecto (“MainMenuBar”) en la anterior captura. Ya dentro del Editor de menús, podremos recorrer cualquiera de las entradas disponibles tal y como haríamos en el caso de una aplicación que ya estuviese ejecutándose; y al seleccionar cualquier elemento concreto de las diferentes entradas será cuando podamos alterar sus propiedades en la ventana Inspector:

Ventana de Inspector para un MenuItem

Cada entrada del menú, con independencia del nivel al que se encuentren en la jerarquía, es en Xojo una instancia de la clase MenuItem y, por supuesto, también podremos trabajar con ellos desde el código, ya sea para modificar sus propiedades, crearlos o eliminarlos entre otras acciones.

Entre las principales propiedades que podemos modificar en el Inspector, cabe señalar la asignación de un atajo de teclado y que puede ser específico en función de las plataformas (OS X y Windows/Linux), así como la asociación de un icono y su visibilidad. Si marcamos el MenuItem como no visible, entonces este no aparecerá en la barra de menús durante la ejecución de la aplicación; especialmente útil si posteriormente queremos que este sea visible desde nuestro código en función de cual sea el sistema operativo sobre el que se esté ejecutando la aplicación.

Obviamente, y tal y como ocurre con el resto de los elementos UI de proyecto en Xojo, en el apartado Inspector también podremos modificar la propiedad Text que se corresponde con el texto que verán los usuarios de nuestras aplicaciones para el MenuItem cada vez que desplieguen el menú, así como la propiedad Name que se corresponde con el nombre que utilizaremos desde nuestro código para referirnos a dicha instancia. Por supuesto, podemos seguir los mismos principios de localización proporcionados por Xojo para que los MenuItem muestren el texto correspondiente en función del idioma seleccionado por el usuario.

Una práctica que utilizo en mis proyectos es la de completar únicamente el texto correspondiente a la propiedad Text. De este modo el IDE se encarga de rellenar automáticamente la propiedad Name y quedan todos los nombres más unificados, lo que mejora la posterior identificación desde el código.

En cuanto a la propiedad AutoEnable, indica que el MenuItem en cuestión aparecerá como activo sin necesidad de que lo indiquemos expresamente desde un manejador de evento EnableMenuItems; tan solo será preciso que añadamos un manejador de evento (Menu Handler) para este en nuestro programa. Piensa en dicha propiedad como en una “comodidad” proporcionada por el entorno de desarrollo. Siempre podemos tener un control total sobre la activación de un MenuItem desde EnableMenuItems. Así, por ejemplo, podremos indicar que una opción de menú se muestre como habilitada solo cuando se encuentre seleccionado un determinado elemento de nuestra aplicación.

No te preocupes por ahora sobre estas cuestiones, ya las veremos más adelante con mayor detalle.

Opciones de edición para una barra de menús en Xojo

Borrar una entrada del menú es sencillo: selecciona el elemento a borrar y pulsa la tecla de borrado en tu ordenador. El resto de acciones se llevan a cabo mediante el grupo de botones disponibles en la barra de herramientas del editor (alguno de ellos disponibles solo si se encuentra seleccionad un MenuItem). De izquierda a derecha, los botenes permiten realizar las siguientes acciones:

 

  • Añadir una nueva entrada de menú de primer nivel en la barra de menús.
  • Añadir un nuevo elemento de menú sobre el MenuItem de primer nivel que esté seleccionado en ese momento.
  • Añadir un elemento visual de separación, y que nos permite mejorar la representación visual de las entradas de menú.
  • Crear un submenú asociado al elemento de menú seleccionado en ese momento.
  • Promocionar el elemento de menú seleccionado como nueva entrada de primer nivel en la barra de menús.

No importa el orden en el que añadas los elementos de menú, siempre podrás reordenarlos con arrastrar y soltar, lo que resulta una importante ventaja.

Activar/Desactivar menús de forma dinámica

Tal y como indicaba anteriormente, es bastante probable que algunos de los elementos de menú de cualquier aplicación deban de reaccionar de forma dinámica en base a determinadas acciones. Esto es lo que podemos realizar implementando el manejador de evento EnableMenuItems en los componentes UI de nuestro proyeto, tales como las ventanas, cualquier control gráfico capaz de recibir el foco (es decir, capaz de recibir eventos de interacción del usuario) y el objeto App que representa la instancia de tipo Singleton de nuestra aplicación.

En la práctica, es frecuente implementar dicho manejador de evento principalmente en las instancias de tipo Window y App, siempre en función de las respondabilidades de cada uno de ellos a la hora de ejecutar la acción asociada con el elemento de menú seleccionado.

Para añadir el manejador de evento, sólo hay que seleccionar en el Navegador de Proyecto el elemento sobre el que se desee incorporar (por ejemplo Window1) y elegir la opción Insert > Event Handler… desde la barra de menús o bien las opciones equivalentes disponibles en la barra de herramientas o en el menú contextual.

En el Editor de Código resultante ya solo tendremos que introducir el código encargado de activar/desactivar aquellos menús en los que estemos interesados. Por ejemplo, la sentencia:

editCopy.enabled = textArea1.text.selText > 0

Se encargará de mostrar como activo el elemento de menú “editCopy” solo en aquellos casos en los que el control de entrada de texto “TextArea1” tenga parte de su texto seleccionado con una longitud mayor de 0 caracteres. Sencillo, ¿verdad?

Es posible que te preguntes cuándo se ejecuta el código incluido en dicho manejador, la respuesta es que se hará siempre que el usuario haga clic sobre la barra de menús durante la ejecución de nuestra aplicación. Y recuerda que en el caso de que dos o más elementos de la aplicación incorporen el manejador de eventos EnableMenuItems, se ejecutará el código asociado al manejador de eventos que tenga el foco en ese momento.

Ejecutar código en respuesta a una entrada de menú

Ya hemos visto como podemos activar y desactivar los elementos de menú a voluntad, pero… ¿y cómo podemos indicar el código que ha de ejecutar cada uno de ellos? Esta es la tarea que se lleva a cabo implementando un nuevo evento sobre el control responsable. Se trata de los Menu Handler.

Ejemplo de menú personalizado en Xojo

Pongamos por caso que hemos añadido a la barra de menús una entrada de primer nivel con el nombre “Saludar” y, bajo este, una nueva entrada de menú con el texto “Hola mundo”. Para asociar el código a ejecutar en respuesta de que el usuario seleccione nuestra entrada de menú “Hola mundo”, podemos seleccionar “Window1” en el Área de Navegación del proyecto y elegir a continuación Insert > Menú Handler.

Asignar nombre de MenuItem para la ejecución de código en un Menu Handler

En respuesta, el IDE de Xojo nos llevará al Editor de Código para el nuevo manejador de menú. En él hemos de introducir en el apartado Name del Inspector el nombre del MenuItem sobre el que queremos asociar el código (en nuestro ejemplo será “SaludarHolaMundo”). ¡Verás que la función de autocompletado del IDE de Xojo resulta de gran ayuda! Otra opción consiste en desplegar el menú Combo y recorrerlo para seleccionar la entrada correspondiente.

Por último, sólo restaría introducir el código a ejecutar propiamente dicho:

msgBox “¡Hola Mundo!"

En este caso se trata de poco código, de modo que podemos ejecutarlo directamente desde el manejador de menú. Sin embargo, en el caso de que la respuesta del menú fuese la ejecución de código más complejo, entonces te recomiendo que te limites a incluir la llamada al método respondable de ejecutar el código propiamente dicho.

Por último, recuerda incluir como línea final siempre la sentencia “Return True” para evitar que el evento se propague por la cadena de respuesta de la aplicación. Es la forma de indicar que ya has respondido al evento y que no es preciso que sea gestionado por ningún otro componente del programa que implemente también un manejador de menú para el mismo MenuItem.

Crear menús dinámicos en Xojo

Hasta ahora hemos visto situaciones en las que la edición, habilitación y respuesta de los menús parten de una situación conocida; es decir prevista desde el punto inicial del diseño de la aplicación. Ahora bien, ¿qué ocurre en aquellos casos en los que no podamos anticipar qué ítems de menú hemos de crear? Por ejemplo, un caso clásico sería la construcción de un menú de fuentes, dado que no sabemos previamente cuantos o qué fuentes estarán instaladas en el equipo del usuario que vaya a ejecutar la aplicación.

En estas situaciones lo primero que tenemos que hacer es crear nuestra propia subclase a partir de la clase MenuItem, dado que este es el único modo que tendremos para ejecutar código asociado a los elementos de menú para los que no es posible definir un Manejador de Menú (Menu Handler) de forma anticipada. Veamos como hacerlo mediante un ejemplo.

Utiliza la opción Insert > Class para añadir una nueva clase al proyecto. Selecciona el elemento recién creado en el Área de Navegación y, en el panel Inspector asociado, introduce “MiMenuItem” como nombre de la clase y “MenuItem” en el campo Super, de modo que estaremos indicando así que se trata de una clase derivada de la clase MenuItem, heredando su comportamiento. De hecho, cuando completes el campo Super verás como el ítem cambia su icono por el típico de un MenuItem en el Navegador de Proyecto.

Ahora con el elemento MiMenuItem seleccionado en la Navegador de Proyecto, accede al menú contextual y selecciona la opción Add to “MiMenuItem” > Event Handler…

Añadir manejador de evento Action a la subclase MenuItem

En la ventana resultante, selecciona el evento Action. El código asociado con dicho evento será el que se ejecute cada vez que el usuario de nuestra aplicación seleccione un elemento de menú basado en dicha clase.

En el Editor de Código resultante, introduce la siguiente línea:

MsgBox me.Text
Return true

En el Navegador de Proyecto, selecciona el elemento MainMenuBar para acceder al Editor de Menús y añade un nuevo menú de primer nivel con el texto Fuentes (su propiedad Name debería de ser “FuentesMenu”).

A continuación, selecciona el elemento Window1 y añade el evento Open para incluir el siguiente código:

dim m as MiMenuItem
for n as integer = 0 to FontCount -1
m = new MiMenuItem
m.Text = font(n)
FuentesMenu.Append m
next

¡Listo! Ya puedes ejecutar la aplicación. Comprobarás que al desplegar el menú Fuentes este listará todas las fuentes disponibles en el equipo, elementos de menú que hemos creado en tiempo de ejecución. Selecciona cualquiera de las entradas y aparecerá una ventana de mensaje mostrando el texto del elemento de menú seleccioando, tal y como hemos indicado en el evento Action de nuestra subclase MiMenuItem derivada de MenuItem.

Menú de fuentes en Xojo, creado en tiempo de ejecución

Conclusiones

Los vistos en esta entrada son los aspectos básicos en la edición, uso y respuesta de los elementos de menús para nuestras aplicaciones de escritorio. Confío que lo hayas encontrado interesante y que haya despejado cualquier tipo de duda que pudieses tener a la hora de planificar e implementar tus propias barras de menú en las aplicaciones de escritorio creadas con Xojo.

4 comentarios en “Crear y operar con menús en Xojo

  1. wilkins

    Hola, quiero llamar un formulario desde el menu bar, me puedes ayudar por favor!!!

    Gracias de ante mano.

    1. Javier Rodriguez

      Claro!

      Tal y como se indica en el artículo y en el vídeo que lo acompaña, puedes “interceptar” la selección de las entradas de menú a través de los Menu Handler (has de añadir un Menú Handler para el menu ítem que desees). Luego en el Editor de Código sólo resta hacer un “nombreDeLaVentana.show” ¡y listo!

      Dime si necesitas ayuda adicional

      Javier

  2. Antonio José Masiá

    Buenas Javier,

    ¿Cómo puedo implementar un icono (a la derecha en la barra de menus de OSX) para que cuando pulse se despliegue una ventana?

    Gracias!

    1. Javier Rodriguez

      Hola Antonio,

      Si te refieres a crear un icono en la barra de menús del Finder, actualmente utilizo la librería OpenSource MacOSLib en mis apps. Si en vez de un menú quieres mostrar una ventana al hacer “clic” sobre el icono, entonces en el evento del menú del Finder creado has de obtener las coordenadas globales del cursor del ratón y utilizarlas para mostrar la ventana con el cálculo que desees realizar a partir de dichas coordenadas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *