Más sobre ficheros de recursos

También en lo que respecta a los ficheros de recursos hay más cosas que contar. Para empezar, además de la sentencia MENU existe otra sentencia para crear recursos de menús extendidos, que incorporan características introducidas en Windows 95. Pero de todos modos, aún no hemos visto todo sobre la sentencia MENUITEM.

Sentencia MENUITEM y POPUP

La sintaxis de MENUITEM es:

MENUITEM texto, resultado, [lista_de_opciones]

Y la de POPUP es:

POPUP texto, [lista_de_optiones]
BEGIN
    definiciones_de_item
    ...
END

Hasta ahora nunca hemos usado las opciones (que evidentemente son opcionales). Ahora que hemos visto las marcas y los estados de los ítems de menú, veremos que esas opciones pueden ser interesantes:

Ficheros de recursos
Fucheros de recursos
  • GRAYED: el nombre del ítem esta inicialmente inactivo y aparece en el menú en gris o con el texto del menú ligeramente degradado. En el ejemplo, el ítem "Gris".
  • HELP identifica un ítem de ayuda. Esto hace que se muestre alineado a la derecha. En el ejemplo, todo el POPUP "Pruebas" ha sido definido con esta opción.
  • INACTIVE el nombre del ítem se muestra, pero no puede ser seleccionado. En el ejemplo, el ítem "Inactivo".
  • MENUBREAK coloca el ítem de menú en una nueva línea en ítems de menú. En menús pop-up, coloca el ítem de menú en una nueva columna sin división entre las columnas. En el ejemplo es el caso del ítem "Break".
  • MENUBARBREAK lo mismo que MENUBREAK excepto que para menús pop-up, separa la nueva columna de la anterior con una línea vertical. En el ejemplo, "Bar break".
  • CHECKED: el ítem tiene una marca de verificación junto a él. En el ejemplo, el ítem "Prueba 2" está definido con esta opción. Esta opción sólo se aplica a ítems de menú, no a popups.
menu MENU
BEGIN
 POPUP "&Pruebas"
 BEGIN
  MENUITEM "&Ayuda", 500
  MENUITEM "&Gris",  501, GRAYED
  MENUITEM "&Inactivo", 502, INACTIVE
  MENUITEM "Ba&r Break", 503, MENUBARBREAK
  MENUITEM "Prueba &2", 504, CHECKED
  MENUITEM "Prueba &3", 505
  MENUITEM "&Break", 506, MENUBREAK
  MENUITEM "Prueba &4", 507
  MENUITEM "Prueba &5", 508
 END
END

Detalles sobre cadenas de ítems

En cuanto a las cadenas de caracteres que se usan en los ítems, hay varias secuencias de caracteres que nos permiten cierto control sobre el aspecto de las cadenas.

Ya hemos visto que se puede seleccionar una de las letras para que se pueda activar el ítem mediante el teclado, basta como poner el carácter & delante de la letra elegida.

Si queremos que el carácter & aparezca como parte del texto del ítem, habrá que duplicar el carácter &&, por ejemplo "&Carácter &&" aparecerá como Carácter &.

Del mismo modo, para incluir comillas dobles dentro de la cadena, se deben escapar mediante la secuencia \", por ejemplo "Cadena \"prueba\"" aparecerá como Cadena "prueba".

Por último, podemos usar la secuencia \a para justificar el texto a la derecha, y la secuencia \t para introducir un tabulador. Estas secuencias se suelen usar para añadir la información sobre las teclas aceleradoras de menú, como vimos en el capítulo anterior.

Sentencia MENUEX

Como habrás visto, en las sentencias anteriores no es posible crear menús con todas las características que hemos explicado. Por ejemplo, no se pueden crear ítems con la marca de "radio" en lugar de la de "check". Los menús evolucionaron a partir de Windows 95, y pora adaptarse a ello, se creó una nueva sentencia: MENUEX.

La sintaxis es la siguiente:

menuID MENUEX
BEGIN
    [{[MENUITEM itemText [, [id] [, [type [| state]]]] |
    [POPUP itemText [, [id] [, [type [| state] [, helpID]]]]
    BEGIN
        popupBody
    END]} ...]
END

En realidad, la sintaxis de MENUEX es la misma que la de MENU, lo que cambia es que las sentencias MENUITEM y POPUP tienen más posibilidades dentro de una sentencia MENUEX.

Como vemos, en el caso de MENUITEM, tanto el identificador, como el tipo, como es estado son opcionales.

Además, tanto para el tipo como para el estado, existen más posibilidades que en el MENUITEM anterior, en concreto podemos usar las constantes de tipo definidas en el fichero "winuser.h" para la estructura MENUITEMINFO, que empiezan con MFT_. Para eso hay que incluir ese fichero de cabecera en el fichero de recursos.

Estas constantes son:

  • MFT_BITMAP: muestra el ítem de menú usando un mapa de bits. En realidad, esta constante no se puede usar en ficheros de recursos, y se debe modificar en el fichero ejecutable. Veremos esto más abajo.
  • MFT_MENUBARBREAK: coloca el ítem de menú en una línea nueva (para una barra de menú) o en una columna nueva (para un menú desplegable, un submenú o un menú de atajo). Para este último caso, una línea vertical separa la nueva columna de la antigua. Equivale a MENUBARBREAK de MENU.
  • MFT_MENUBREAK: coloca el ítem de menú en una línea nueva (para una barra de menú) o en una columna nueva (para un menú desplegable, un submenú o un menú de atajo). Para este último caso, la columna no se separa con una línea vertical. Equivale a MENUBREAK.
  • MFT_OWNERDRAW: asigna la responsabilidad del trazado del ítem de menú a la ventana a la que pertenece el menú. Esta bandera tampoco se puede usar en un fichero de recursos.
  • MFT_RADIOCHECK: muestra los ítems marcados usando la marca del radio-button en lugar una marca de chequeo si el miembro hbmpChecked es NULL. Esta bandera tampoco se puede usar en un fichero de recursos.
  • MFT_RIGHTJUSTIFY: justifica a la derecha el ítem de menú y los ítems siguientes. Este valor sólo es válido si el ítem de menú está en una barra de menú. Equivale a HELP.
  • MFT_SEPARATOR: especifica que el ítem de menú es un separador. Un ítem de menú separador aparece como una línea horizontal divisora. No es válido en barras de menú. Equivale al SEPARATOR de MENU. Tampoco se puede usar en ficheros de recursos, para poner separadores basta con usar una cadena nula, ("").
  • MFT_STRING: muestra el ítem de menú usando una cadena de texto. Es el valor por defecto, no es necesario especificarlo.

Para el estado podemos usar las constantes declaradas en "winuser.h" con el prefijo MFS_.

  • MFS_CHECKED: marca el ítem de menú. Equivale a CHECKED.
  • MFS_DEFAULT: especifica que el ítem de menú es el ítem por defecto. Esta bandera no se puede usar en un archivo de recursos. Veremos esto más abajo.
  • MFS_DISABLED: inhibe el ítem de menú de modo que no puede ser seleccionado, pero no lo oscurece. Equivale a INACTIVE.
  • MFS_ENABLED: desinhibe el ítem de menú de modo que pueda ser seleccionado. Este es el estado por defecto, y no es necesario especificarlo.
  • MFS_GRAYED: inhibe el ítem de menú y lo oscurece de modo que no puede ser seleccionado. Equivale a GRAYED.
  • MFS_HILITE: resalta el ítem de menú. Esta bandera tampoco se puede usar en ficheros de recursos.
  • MFS_UNCHECKED: quita la marca del ítem de menú. Este es el estado por defecto, tampoco es necesario especificarlo.
  • MFS_UNHILITE: elimina el resaltado del ítem de menú. Este es el estado por defecto, tampoco es necesario especificarlo.
menu MENUEX
BEGIN
 POPUP "&Principal"
 BEGIN
  MENUITEM "&Inhibir",   CM_INHIBIR, MFT_STRING
  MENUITEM "&Oscurecer", CM_OSCURECER, MFT_STRING
  MENUITEM "&Activar",   CM_ACTIVAR, MFT_STRING
  MENUITEM "" // MFT_SEPARATOR
  MENUITEM "O&pción",    CM_OPCION, MFT_STRING
 END
 POPUP "&Pruebas",0,MFT_STRING | MFT_RIGHTJUSTIFY
 BEGIN
  MENUITEM "&Ayuda", 500, MFT_STRING
  MENUITEM "&Gris",  501, MFT_STRING, MFS_GRAYED
  MENUITEM "&Inactivo", 502, MFT_STRING, MFS_DISABLED
  MENUITEM "Ba&r Break", 503, MFT_STRING | MFT_MENUBARBREAK
  MENUITEM "Prueba &2", 504, MFT_STRING, MFS_CHECKED
  MENUITEM "Prueba &3", 505, MFT_STRING, MFS_UNCHECKED
  MENUITEM "&Break", 506, MFT_STRING | MFT_MENUBREAK
  MENUITEM "Prueba &4", 507, MFT_STRING
  MENUITEM "Prueba &5", 508, MFT_STRING
 END
END

Nota: He encontrado tres errores en la documentación de Windows.
1. Las definiciones de las constantes MFS_DISABLED y MFS_GRAYED, dentro del fichero "winuser.h" actualmente están modificadas. La primera macro debe valer 2, y la segunda 1; actualmente ambas valen 3.
2. En la documentación original de MENUEX dice que los valores de tipo y estado deben estar separados con una coma. He comprobado que en algunas versiones antiguas del compilador de recursos, para que todo funcione adecuadamente, estos valores se deben combinar usando el operador de bits OR (|) o el de suma (+).
3. Los separadores dentro de menús POPUP no se consiguen con la bandera de tipo MFS_SEPARATOR, sino usando una cadena nula ("").

Resumamos un poco:

Items marcados y no marcados

Bueno, ya hemos visto que cuando definimos recursos de menú podemos elegir el estado incial de las marcas de chequeo. En el caso de MENU mediante los modificadores CHECKED para marcado, y nada para no marcados. En el caso de MENUEX mediante las banderas MFS_CHECKED y MFS_UNCHECKED.

Ya hemos visto que no podemos hacer nada para que los ítems sean de tipo radio en el fichero de recursos. Esta característica se modifica durante la ejecución.

Items activos, inactivos u oscurecidos

Por defecto, los ítems de menú estarán activos, pero si queremos crearlos inactivos u oscurecidos, en el caso del recurso MENU usaremos los modificadores INACTIVE o GRAYED respectivamente. En el caso del recurso MENUEX las banderas MFS_DISABLED para inhibido, o MFS_GRAYED para oscurecido.

Separadores y líneas de ruptura

Existen varias opciones para separar ítems, ya sea horizontalmente o verticalmente, y en barras de menú o en menús desplegables.

En barras de menú, y con recursos MENU podemos usar los modificadores MENUBREAK o MENUBARBREAK para cambiar de línea un ítem o un popup. También podemos usar el modificar HELP para trasladar un ítem o popup a la derecha de la barra de menú.

En el caso del recurso MENUEX, el mismo efecto se consigue con las banderas MFT_MENUBREAK, MFT_MENUBARBREAK o MFT_RIGHTJUSTIFY, respectivamente.

Dentro de los menús popup, los modificadores del recurso MENU tienen efectos diferentes. El modificador MENUBREAK hace que el siguiente ítem se sitúe en una nueva columna, y el modificador MENUBARBREAK lo mismo, pero se añade una línea vertical separadora.

Los separadores horizontales, en el caso del recurso MENU se consiguen con una línea MENUITEM SEPARATOR, estos separadores son útiles para agrupar ítems, o grupos de opciones del tipo checkitems o radioitems.

En el caso de recursos MENUEX los separadores verticales se consiguen con las banderas MFT_MENUBREAK y MFT_MENUBARBREAK, y los horizontales con una cadena vacía MENUITEM "".

Nota: SEPARATOR es probablemente una etiqueta para la cadena "", y son intercambiables.

Cargar recursos

Para cargar un recurso de menú tenemos varias opciones, como ya vimos en el capítulo 5. Lo más simple es usar un menú de clase, asignando la cadena con el nombre del menú al miembro lpszMenuName de la estructura WNDCLASSEX o WNDCLASS, por ejemplo:

wincl.lpszMenuName = "menu";

También podemos cargar recursos de menú y usar un manipulador para referirnos a ellos durante la ejecución, mediante la función LoadMenu:

    HMENU hMenu;
...
    hMenu = LoadMenu(hThisInstance, "menu");

Este menú se puede asignar a una ventana mediante la función SetMenu o al crear la ventana con las funciones CreateWindow o CreateWindowEx, pero más abajo veremos que existen otras posibilidades.