Curso básico de programación en Visual Basic

  Lección 29

Menús, submenús, PopupMenús

 

Realizamos programas para la gestión de empresas. Empresas medianas y pequeñas. Programas de contabilidad, cartera de pedidos clientes proveedores, facturación control de albaranes, tesorería cartera de cobros y pagos y estadísticas.

Nuestro agradecimiento a todos los que por unas causas o por otras visitan nuestra web. Gestión de empresas PYMES. Curso de programación de Visual Basic.


 

Si has notado que la entrega anterior está "inacabada" estás en lo cierto... la verdad es que gracias a uno de los "típicos" despistes que me caracterizan, se me fue un poco la "olla" y creí haberla acabado, pero... no fue así, por tanto, espero que no te enfades mucho conmigo y tengas paciencia, que pronto estará terminada... por ahora sigue con lo que hay que al ser un tema diferente no te causará ningún trastorno cerebral... y si te lo causa... ¡bienvenido al club!

Esta entrega también ha sido "mecanografiada" por Encarnica... que ya tiene pasadas a limpio hasta la entrega 32... aunque sólo la parte explicativa, ya que el código me lo deja a mi... que ella aún no sabe programar... así que si hay retrasos en la publicación, es sólo culpa mia...

También quiero daros las gracias, en nombre de Encarni por los que la habéis felicitado por "ofrecerse" a pasar a limpio mis notas "ininteligibles". ¡Gracias otra vez Encarni!

 

Menús, submenús, popupmenús y ajuste de tamaños.

En la entrega de hoy vamos a ver cómo añadir menús a nuestros programas. Para verlo "ejemplarizado" vamos a crear un minieditor (¡por fin!) pero no te hagas ilusiones... será tan simple que casi sólo vamos a utilizar un cuadro de texto y sus posibilidades serán básicamente las que nos de el textbox... bueno, realmente tendrá algunas más... ya veremos.

Para crear el programa, abre un proyecto nuevo, el el form que se crea por defecto, añade un TextBox, asígnale estos valores a las propiedades indicadas:

Propiedad Valor
Multiline True
Scrollbars 3-Both
Left 0
Top 0
Name txtEditor

Multiline para que permita más de una línea de texto; los dos Scrollbars para que podamos escribir líneas de cualquier longitud y que sólo cambien al pulsar Intro; Left y Top, para que se posicione en la esquina superior izquierda del formulario.

 

Crear una barra de estado (StatusBar)

Vamos a añadirle al formulario un Picture para que nos sirva de Statusbar, para ello añade un picture al proyecto, selecciónalo y asígnale la propiedad Align a 2 - Align Bottom para que se pegue a la parte inferior del formulario. Asígnale un valor 315 a la propiedad Height, en la propiedad BorderStyle, asígnale un 0 (sin borde). Selecciona del toolbar una etiqueta haz doble click y se insertará en el formulario. Selecciona la etiqueta y córtala (menú edición / cortar). Selecciona el picture y pega la etiqueta (menú edición / pegar). Asígnale estas valores a las propiedades indicadas: Height = 285, Top = 15, Left = 30, BorderStyle = 1 (con borde).

Ahora vamos a darles nombre a los controles, al TextBox llámalo txtEditor, el Picture será picStatus, el Label se llamará lblStatus.

 

Posicionar los controles automáticamente en el formulario

Antes de empezar a crear los menús, vamos a indicarle al Visual Basic que "posicione" correctamente los controles cuando el formulario cambie de tamaño. Para ello, abre la pantalla del código, selecciona Form de la lista de la izquierda y Resize en la lista de la derecha.

Cada vez que un formulario cambia de tamaño se ejecuta el evento Form_Resize, por tanto este es el sitio en el que tendremos que codificar para adaptar los controles al tamaño adecuado. Lo que vamos a hacer es ajustar el tamaño de la etiqueta al tamaño del Picture y el TexBox para que ocupe todo el tamaño restante.

Pero sólo haremos los cálculos cuando el form no se minimice, ya que si está minimizado, no se ve nada, así que para que vamos a ajustar el tamaño de algo que no se ve; para indicarle al VB que sólo ejecute el código cuando no vaya a minimizar la aplicación usaremos la propiedad WindowState, si esta es diferente de vbMinimized querrá decir que no se ha minimizado, así pues, añade este código:

' Sólo cuando no esté minimizado el formulario
If WindowState <> vbMinimized Then

Y ahora empezaremos a ajustar los tamaños:
El label será igual de ancho que el PicStatus menos 60, para que tenga un poco de "respiro" por los lados:

'
lblStatus.Width = picStatus.ScaleWidth - 60

esta es simple, ahora haremos lo mismo lo mismo con el txtEditor:

'
txtEditor.Width = ScaleWidth

el alto será el alto del form menos el alto del PicStatus:

'
txtEditor.Height = ScaleHeight - picStatus.Height

y ya está. Se supone que en tiempo de diseño asignaste 0 a las propiedades Left y Top del txtEditor, aunque si quieres, puedes hacerlo en este mismo evento:

'
txtEditor.Move 0, 0

eso es lo mismo que haber asignado 0 a las propiedades Left y Top… es más rápido cambiar el tamaño de un control con Move que asignando cada una de las propiedades por separado, ya que se usa un sólo método en lugar de 4 asignaciones a propiedades, así pues, podríamos haber cambiado el tamaño del txtEditor de esta otra forma, aunque seguramente sería menos "instructivo":

'
txtEditor.Move 0, 0, ScaleWidth, ScaleHeight - picStatus.Height

Vamos a probarlo :

Pulsa F5 y cambia el tamaño de la ventana, verás como se "adaptan" los controles… aunque el label no parece enterarse ¿verdad?

 

Para que el label se ajuste al tamaño del picture, hay que ajustar ese tamaño en el evento Resize del picStatus:

'
Private Sub picStatus_Resize()
    ' Sólo cuando no esté minimizado el formulario
    If WindowState <> vbMinimized Then
        ' Aquí se ajustará el tamaño del label
        ' cuando cambie el del picStatus
        lblStatus.Width = picStatus.ScaleWidth - 60
    End If
End Sub

Algo sobre los tamaños de los controles: Diferencia entre Height/Width y ScaleHeight/ScaleWidth

Como habrás notado, para ajustar el ancho y alto, se está usando ScaleWidth y ScaleHeight, aunque para calcular el alto del textbox también se usa picStatus.Height, en cuanto te explique que significan estas propiedades, seguro que lo entiendes.

ScaleWidth y ScaleHeight son propiedades que nos informan del ancho y alto "interno" del formulario o control, es decir lo que miden sin contar el borde. Width y Height, por otro lado, nos dicen que el ancho y alto "externo" del form o control.

Cuando se calcula el alto del txtEditor necesitamos saber el alto interno del formulario (ScaleHeight) al que hay que restarle el alto total de picStatus (picStatus.Height). Si hubiésemos usado Height en el lugar de ScaleHeight, los cálculos no nos hubiesen salido correctos, ya en el valor devuelto por esa propiedad nos indicaría el alto total del form. Ahora mismo, tal como está el programa habría poco diferencia, aunque aún así no se ajustaría perfectamente, "desajuste" que quedaría demasiado evidente en cuanto añadamos menús. (¿menús? No era de eso de lo que iba a tratar esta entrega).

Otro detalle es que para referirnos al alto y ancho "interno" del formulario, lo hemos usado sin indicar nada más, esto siempre es así cuando hagamos referencia a una propiedad de un objeto, (en este caso un formulario), y el código se ejecuta "dentro" de ese formulario. Sin embargo cuando hacemos referencia a las propiedades de otros controles, (incluso de otro formulario), tendremos que anteponer el nombre de ese control delante de la propiedad o método, para que el VB sepa a que control nos estamos refiriendo.

Borra la línea que cambiaba el tamaño de la etiqueta en el evento Form_Resize y vuelve a pulsar F5, cambia el tamaño del formulario, esta vez si que se adapta bien el lblStatus dentro del picture que la contiene.

Ya puedes detener el programa, pulsando en la "x" del form. Haz que se muestre el fomulario ya que es necesario para poder añadir menús a nuestro "mini-editor".

 

Añadir menús a un formulario

Como habrás observado en todas las aplicaciones de Windows, los menús se muestran en la parte superior de las aplicaciones, esto no es ningún descubrimiento, excepcional pero… la cuestión es que si se muestran en la parte superior ¿tendremos que hacer un nuevo cálculo al cambiar el tamaño del formulario?

La respuesta es: no.

Al añadir menús a nuestro formulario, el tamaño de éste se ajusta automáticamente y no tendremos que tener en cuenta el espacio que ocupa para "ajustar" los controles que tengamos en él. Es decir, que el código del Form_Resire sigue siendo válido con o sin menús.

Una vez aclarado este punto, antes de empezar a añadir menús, otro poco de teoría… pero no te asustes, no es demasiado la teoría, sólo para aclarar "conceptos".

Cuando creamos menús tenemos varios "niveles", normalmente son dos: el menú principal que siempre está visible en la parte superior y los elementos que se muestran cuando hacemos click (o pulsamos) en ese menú principal. Cada vez que pulsamos en un elemento de la "lista" de menús principal se muestran los que "cuelgan" de él. Habrás observado que muchos de los elementos de los menús, tanto principales como secundarios, tienen una letra subrayada, eso quiere decir que pulsando Alt más esa letra, se despliega o selecciona esa opción del menú, es como si pulsáramos con el ratón. Cuando empiece con la explicación verás cómo podemos crear nuestras propias letras de acceso, incluso cómo añadir "accesos rápidos" a algunas de las opciones de los menús, todo esto lo veremos ahora mismo.

 

Cómo añadir menús a nuestro formulario (ahora si)

Para poder "diseñar" los menús, tienes que tener visible el formulario en el que mostraremos los menús, así que si el formulario no está mostrado, haz que se muestre, (haciendo dobleclick en la ventana del explorador de proyectos)

Para entrar en modo de diseño de menús, puedes hacerlo de dos formas: seleccionando del menú Tools (Herramientas) la opción Menu Editor… o pulsando el icono img29_01.gif (138 bytes) de la barra de herramientas. Te mostrará un cuadro de diálogo como el que sigue:

El editor de menús del Visual Basic

 

Las partes más importantes son:
Caption/Descripción que es el texto que se mostrará,
Name/Nombre del menú que será donde escribamos el código a ejecutar cuando se seleccione ese menú.

Vamos a empezar por añadir un menú "Fichero", (o archivo si así lo prefieres), en este menú tendremos las opciones de Abrir, Guardar, Guardar como y Salir, después añadiremos otras, según convenga. También tendremos otro menú principal llamado Edición con las clásicas opciones de ese tipo de menú: Deshacer, Cortar, Copiar, Pegar, etc.

Pero empecemos por el de fichero:

Escribe en el "Caption", &Ficheros, el signo & le indicará al Visual Basic que muestre subrayada la letra que sigue a ese signo, de esa forma se podrá acceder pulsando Alt y la letra subrayada, es decir Alt+F

En el nombre del menú escribe: mnuFic y pulsa Intro o en el botón Siguiente. Se "limpiarán" las casillas de texto y estará listo para escribir las opciones de este menú:

Escribe en Caption: &Abrir... y en nombre mnuFicAbrir los tres puntos suspensivos es una norma recomendable, que indica que se mostrará un cuadro de diálogo, acostúmbrate a seguirla, de esta forma tus aplicaciones tendrán un aspecto "standard windows" (realmente no es un estándar de windows, sino una norma anterior anterior, pero…)

Después de la opción Abrir vamos a añadir Guardar, por tanto en el caption del menú escribimos &Guardar y en el nombre de esa opción: mnuFicGuardar, en este caso no añadimos los tres puntos seguidos ya que lo habitual en las opciones guardar, es guardar sin preguntar, salvo que aún no se le haya dado nombre al fichero.

Como habrás observado cada vez que añades una opción se va mostrando en la lista inferior. Antes de seguir vamos a ver cómo quedan nuestros menús.

Pulsa el botón "aceptar" del cuadro de diálogo del "diseñador de menús".

¡Sorpresa!
Como puedes observar, tenemos tres opciones "principales": Ficheros, Abrir… y Guardar, pero esta no era la intención, ya que Abrir y Guardar sólo se deberían mostrar al seleccionar el menú Ficheros
¿Qué ha pasado?
Muy fácil, al menos cuando se sabe cómo trabaja esto de los menús, que al no indicarle lo contrario… ¡todos los menús se muestran en la barra principal! ¿cómo podemos crear los submenús (o menús que se muestran al seleccionar un menú)?

Ahora lo veremos, antes de hacerlo, en tiempo de diseño, es decir, sin pulsar F5, pulsa en el menú Fichero. Se mostrará la ventana de código, el combo de en la parte izquierda se mostrará mnuFic y en el de la derecha verás que es el evento click, por tanto estaremos en el procedimiento mnuFic_Click. Todo lo que escribas en este menú se ejecutará cuando selecciones esta opción. No escribas nada, cierra la ventana de código para volver a mostrar el formulario.

Vamos a hacer que los menús se muestren como deben: al seleccionar Ficheros que se despliegue el menú con las opciones Abrir, Guardar, etc.

Entra en el diseño de menús, (esto tendrás que hacerlo siempre que quieras añadir nuevas opciones de menús o modificar las ya existentes.)

Si te fijas en la lista inferior, verás que las tres opciones que tenemos están alineadas a la izquierda.
Selecciona Abrir en la lista inferior, comprobarás que se "rellenan" las casillas con la descripción y el nombre del menú, eso nos indica que está seleccionada esa opción y que cualquier cambio que hagamos, se hará en esa opción. Sé que todo esto es evidente, pero… por si no lo habías captado… ahora pulsa en la flecha que señala a la derecha, esto hará que la opción seleccionada se desplace a la derecha, esto se muestra por tres puntos delante de Abrir, no los confundas con los tres puntos que nosotros le añadimos al final.

Haz lo mismo con "Guardar"

Cierra el cuadro de diálogo y veras que ahora sólo se muestra el menú Ficheros. ¡Bien! ¡Ya tenemos lo que queríamos! Selecciona ese menú y verás que se muestran las dos opciones que hemos añadido; en esta ocasión no se muestra la ventana de código, pero ya veremos que e evento "sigue operativo".

Pulsa en la opción "Abrir..." y en esta ocasión se mostrará la ventana de código con el procedimiento: "mnuFicAbrir_Click", para comprobar que funciona vamos a añadir un mensaje que se mostrará cuando seleccionemos esta opción:

'
Private Sub mnuFicAbrir_Click()
    ' Abrir
    MsgBox "Esta es la opción Abrir..."
End Sub

Ahora para comprobarlo, pulsa F5 y selecciona el menú Ficheros, se mostrarán las dos opciones que tenemos en este menú: Abrir y guardar. Selecciona Abrir y verás que se muestra el mensaje, lo cual quiere decir que todo está bien.

Cierra la aplicación y vuelve a mostrar el formulario para añadir más opciones a los menús; así que haz que se muestre el diseñador de menús.
Selecciona la última de las opciones de la lista y pulsa en el botón Siguiente para que podamos añadir más opciones. Escribe G&uardar como... en la descripción y mnuFicGuardarComo en el nombre. Si esta nueva opción se muestra en la lista totalmente a la izquierda, pulsa en la flecha de identación a la derecha para que esté al mismo nivel que las otras dos, es decir que tenga tres puntos delante del Caption que le hemos dado.
Pulsa de nuevo en el botón Siguiente, ahora tendrás que escribir un guión, (signo menos), en la descripción del menú, en el nombre del mismo escribe: mnuFicSep1, no sirve de nada, ya que las líneas "divisorias" no se pueden seleccionar, pero deben tener un nombre. Lo que debes "recordar" es que si se indica un "-" en la descripción del menú, estamos indicándole al VB que lo que queremos es que muestre una línea de división. Pulsa en siguiente y escribe: &Salir y mnuFicSalir (ya no es necesario que te diga dónde debes escribirlo, ¿verdad?)

Ya tenemos las opciones del menú Ficheros, ahora vamos con el menú de edición. Añade este menú a continuación de Salir, escribe &Edición en el Caption y mnuEdit en el nombre. Cuando lo hayas escrito verá que está debajo de Salir y con los tres puntos delante, si lo dejamos así, no se mostrará en la barra principal de menús, sino que será una opción más del menú Ficheros, y eso no es lo que queremos, por tanto, pulsa en la flecha que señala a la izquierda para que se pegue totalmente a la izquierda, y desaparezcan los puntos suspensivos que hay delante del Caption. Porque como ya vimos antes, las opciones que se muestran en la lista y que están sin los puntos suspensivos son las que se mostrarán en la barra de menús. Antes de añadir opciones al menú de edición, vamos a modificar las opciones que tenemos, insertaremos una nueva al principio, que servirá para crear un nuevo fichero. El caption, como puedes imaginar, será Nuevo y el nombre del menú será mnuFicNuevo.

Vamos a añadirla: asegúrate que estemos en modo de diseño de menús.

La nueva opción la vamos a insertar al principio, es decir justo antes de Abrir. Por tanto, selecciona Abrir de la lista inferior, pulsa el botón insertar y podrás escribir la descripción: &Nuevo y el nombre del menú: nmuFicNuevo.

Cada vez que quieras insertar una nueva opción puedes hacerlo de esta forma o bien añadiendo la opción al final y después "situarla" en el lugar correspondiente usando las flechas arriba y abajo.
Cuando insertas una opción, usando el botón insertar, la opción insertada tiene la misma "indentación" que la que estaba seleccionada antes de pulsar en insertar. Ya sabes que puedes modificar dicha identación, o desplazamiento, usando las flechas de izquierda y derecha.

Si lo que quieres es borrar un elemento de menú, simplemente la seleccionas y pulsa en "eliminar", aunque esto sólo elimina la opción del menú, no el código que tuviese asociado, lo mismo ocurre cuando eliminamos o cambiamos el nombre de un control: si ya tenía código en algunos eventos, este código sigue estando, pero no en el sitio que debiera… no voy a seguir con esto, ya que lo veremos en otra ocasión, pero al menos cuando le llegue el turno te "sonara"…

Como ya vimos en La entrega 26 se suele seguir unas "normas" a la hora de nombrar a los controles y variables, y si no se "suele" seguir, al menos se recomienda. En este caso los menús se preceden con "mnu" seguido del nombre de menú principal y por último el nombre de la opción. Aunque, como todos los consejos, eres libre de seguir estas normas o de crear las tuyas propias. En mi caso, "intento" seguir éstas que te estoy indicando, aunque algunas veces me las salto, normalmente con la opción "Salir" que simplemente la llamo: mnuSalir, aunque es mejor llamarlo mnuFicSalir para que sepamos que está "incluida" en el menú fic-heros.

Pero en esto de los nombre de los menús, aparte de que los puedes "nombrar" como quieras, existe otra forma de hacerlo.
Ya vimos que se pueden crear "arrays" de controles y que la ventaja era, sobre todo si estaban relacionados, que no necesitamos escribir el mismo código para cada uno de los eventos que queramos interceptar; simplemente usando el índice podríamos distinguir un control de otro; pero siempre, y esa es la ventaja, en un mismo procedimiento de evento. Pues esto mismo se puede hacer con los menús: podemos crear un array.

La única diferencia es que se crea de forma un poco más manual y se hace en la "ventana de diseño de menús".

 

Array de menús

Para ello, se usa el mismo nombre de menú, pero usando un "índice" diferente para cada opción.

El único requisito "obligatorio" es que los elementos de un array de menús han de estar correlativos. Habitualmente se incluyen en ese array todos los elementos de un menú principal… bueno, los que se muestran al seleccionar esa opción. Y esto es lo que vamos a hacer nosotros: incluir en un array todos las opciones del menú edición, que serán las siguientes: Deshacer, separación, cortar, copiar, pegar, separación, seleccionar todo; posteriormente añadiremos más opciones… aunque seguramente será en otra entrega.

El nombre del array será: mnuEditor, el primer elemento, de índice cero, será: Deshacer.

Vamos a añadirlo pasito a pasito, para que no tropieces y te "descalabres".

Supongo que ya estarás en el diseñador de menús y que la opción seleccionada es la última: Edición.
Pulsa en el botón Siguiente y escribe en el Caption: Des&hacer, en el nombre del menú: mnuEditor, (sin acento o tilde... como prefieras llamarlo), en Index escribe 0; pulsa el botón con la flecha a la derecha, para indicar que esta opción pertenece al menú Edición.
Pulsa en siguiente, si no se indenta, ya sabes cómo debes hacerlo; escribe un "-" en el Caption, mnuEditor en el nombre, pero en índice escribe 1, ya que al llamarse de la misma forma el menú, el Visual Basic esperará encontrarse con un índice que lo diferencie. Haz lo mismo con el resto e las opciones y recuerda usar índices correlativos, y por supuesto diferentes...

Cuando hayas introducido todas las opciones, cierra el diseñador de menús… si te da algún tipo de error, puede ser porque no hayas usado el mismo nombre de menú para todas las opciones del menú edición, porque no estén los índices correlativos o porque no estén todos indentados en el mismo nivel, es decir con tres puntos suspensivos a la izquierda (esto es lo que se muestra en la lista y no tienes que escribirlos).

Este sería el aspecto:

Editor de menús con las opciones del menú de Edición

Recuerda que los elementos de un array de menús deber ser correlativos y estar en el mismo nivel de indentación ("osease" pertenecer al mismo menú).

Si todo está bien, al mostrar el formulario en tiempo de diseño, no en ejecución, y pulsar en el menú edición, verás que se muestra las opciones que hemos escrito. Pulsa en cualquier de ellas y verás que siempre se muestra el mismo evento en la pantalla de código:
mnuEditor_Click (Index As Integer)

El parámetro index será el que nos indique cual de las opciones ha sido la que se ha coleccionado.

Para poder hacer cosas diferentes según la opción seleccionada haremos algo como esto:

'
Private Sub mnuEditor_Click(Index As Integer)
    Select Case Index
    Case 0
        ' Deshacer
    Case 2
        ' Cortar
    ' Etc...
    '
    End Select
End Sub

Pero para que resulte más fácilmente entendible y modificable, en lugar de números, vamos a usar constantes, de esta forma, si añadimos o eliminamos alguna de las opciones del menú, sólo tendremos que cambiar el valor de la constante y el resto del código no habrá que modificarlo.

Así pues, en la ventana de código, selecciona la parte general de las declaraciones y añade esto:

'
' Constantes para el menú de Edición.
' Los valores se corresponden con el índice de mnuEditor
Const cEdDeshacer = 0
Const cEdCortar = 2
Const cEdCopiar = 3
Const cEdPegar = 4
Const cEdSeleccionarTodo = 6

Ahora las distintas opciones de "select" en el evento mnuEditor_Click quedarán así:

'
Private Sub mnuEditor_Click(Index As Integer)
    Select Case Index
    Case cEdDeshacer
        '
    Case cEdCortar
        '
    Case cEdCopiar
        '
    Case cEdPegar
        '
    Case cEdSeleccionarTodo
        '
    End Select
End Sub

Con lo cual hemos ganado en "legibilidad" en el código y, aunque aún no lo "sepas", en facilidad a la hora de modificar el código.

El código a usar será el contenido de la siguiente entrega, ya que esta se acaba aquí.

Además del código a usar, veremos cómo añadirle, a las opciones del menú, teclas de acceso rápido, por ejemplo:

Control + X para cortar, etc.

Pero eso será en nuestro siguientes episodio.
Permanezca atento a la pantalla… continuará.

Nos vemos