WinAPI5

download WinAPI5

If you can't read please download the document

Transcript of WinAPI5

Marzo de 2007, Salvador Pozo Coronado Con Clase: http:\winapi.conclase.net

Tabla de contenido.0 Introduccin 0.1 Requisitos previos 0.2 Independencia de la mquina 0.3 Recursos 0.4 Ventanas 0.5 Eventos 0.6 Proyectos 0.7 Convenciones 0.8 Controles 1 Componentes de una ventana 1.1 El borde de la ventana 1.2 Barra de ttulo 1.3 Caja de minimizar 1.4 Caja de maximizar 1.5 Caja de cerrar 1.6 Caja de control de men 1.7 Men 1.8 Barra de men 1.9 Barra de desplazamiento horizontal 1.10 Barra de desplazamiento vertical 1.11 El rea de cliente 2 Notacin hngara 2.1 Ejemplos 3 Estructura de un programa Windows GUI 3.1 Ficheros de cabecera 3.2 Prototipos 3.3 Funcin de entrada, WinMain 3.3.1 Parmetros de entrada de WinMain 3.3.2 Funcin WinMain tpica 3.3.3 Declaracin 3.3.4 Inicializacin

3.3.5 Bucle de mensajes 3.4 Definicin de funciones 4 El procedimiento de ventana 4.1 Sintaxis 4.2 Prototipo de procedimiento de ventana 4.3 Implementacin de procedimiento de ventana simple 4.4 Primer ejemplo de programa Windows GUI 5 Mens 1 5.1 Usando las funciones para insercin tem a tem 5.2 Uso bsico de MessageBox 5.3 Respondiendo a los mensajes del men 5.4 Ejemplo 2 5.5 Ficheros de recursos 5.6 Cmo usar los recursos de men 5.7 Ejemplo 3 6 Dilogo bsico 6.1 Ficheros de recursos 6.2 Procedimiento de dilogo 6.3 Sintaxis 6.4 Prototipo de procedimiento de dilogo 6.5 Implementacin de procedimiento de dilogo para nuestro ejemplo 6.6 Pasar parmetros a un cuadro de dilogo 6.7 Ejemplo 4 7 Control bsico Edit 7.1 Fichero de recursos 7.2 El procedimiento de dilogo y los controles edit 7.3 Variables a editar en los cuadros de dilogo 7.4 Iniciar controles edit 7.5 Devolver valores a la aplicacin 7.6 Aadir la opcin de cancelar 7.7 Ejemplo 5 7.8 Editar nmeros

7.9 Fichero de recursos para editar enteros 7.10 Variables a editar en los cuadros de dilogo 7.11 Iniciar controles edit de enteros 7.12 Devolver valores a la aplicacin 7.13 Ejemplo 6 8 Control bsico ListBox 8.1 Ficheros de recursos 8.2 Iniciar controles listbox 8.3 Devolver valores a la aplicacin 8.4 Ejemplo 7 9 Control bsico Button 9.1 Ficheros de recursos 9.2 Iniciar controles button 9.3 Tratamiento de acciones de los controles button 9.4 Ejemplo 8 10 Control bsico Static 10.1 Ficheros de recursos 10.2 Iniciar controles static 10.3 Tratamiento de acciones de los controles static 10.4 Ejemplo 9 11 Control bsico ComboBox 11.1 Ficheros de recursos 11.2 Iniciar controles ComboBox 11.3 Devolver valores a la aplicacin 11.4 Ejemplo 10 12 Control bsico Scrollbar 12.1 Ficheros de recursos 12.2 Iniciar controles Scrollbar 12.3 Iniciar controles scrollbar: estructura SCROLLINFO 12.4 Procesar los mensajes procedentes de controles Scrollbar 12.5 Procesar mensajes de scrollbar usando SCROLLINFO 12.6 Devolver valores a la aplicacin

12.7 Ejemplo 11 12.8 Ejemplo 12 13 Control bsico Groupbox 13.1 Ficheros de recursos 13.2 Iniciar controles GroupBox 13.3 Devolver valores a la aplicacin 13.4 Ejemplo 13 14 Control bsico Checkbox 14.1 Ficheros de recursos 14.2 Iniciar controles CheckBox 14.3 Procesar mensajes de los CheckBox 14.4 Devolver valores a la aplicacin 14.5 Ejemplo 14 15 Control bsico RadioButton 15.1 Ficheros de recursos 15.2 Iniciar controles RadioButton 15.3 Procesar mensajes de los RadioButtons 15.4 Devolver valores a la aplicacin 15.5 Ejemplo 15 16 El GDI 16.1 Objetos del GDI 17 Objetos bsicos del GDI: El Contexto de dispositivo, DC 17.1 Actualizar el rea de cliente de una ventana, el mensaje WM_PAINT 17.2 Colores 18 Objetos bsicos del GDI: La pluma (Pen) 18.1 Plumas de Stock 18.2 Plumas cosmticas y geomtricas

18.3 Crear una pluma 18.4 Seleccionar una pluma 18.5 Destruir una pluma 18.6 Ejemplo 16 19 Funciones para el trazado de lneas 19.1 Trazado de arcos, funcin Arc 19.2 Curvas Bzier 19.3 Funciones Poly< 19.4 Funcin LineDDA y funciones callback LineDDAProc 19.5 Ejemplo 17 20 Objetos bsicos del GDI: El pincel (Brush) 20.1 Pinceles lgicos 20.1.1 Pinceles slidos 20.1.2 Pinceles de Stock 20.1.3 Pinceles de tramas (Hatch) 20.1.4 Pinceles de patrones 20.2 Crear un pincel 20.3 Seleccionar un pincel 20.4 Destruir un pincel 30.5 Ejemplo 18 21 Funciones para el trazado de figuras rellenas 21.1 Pintando trozos de elipses, funciones Chord y Pie 21.2 Modos de relleno de polgonos 21.3 Ejemplo 19 22 Objetos bsicos del GDI: La paleta (Palette) 22.1 Capacidades de Color de los dispositivos 22.2 Definiciones de valores de color 22.3 Aproximaciones de colores y mezclas de pixels (dithering) 22.4 Mezclas de colores (ROP) 22.5 Paletas de colores

22.6 La paleta por defecto 22.7 Paleta lgica 22.8 Paleta de sistema 22.9 Ejemplo 20 23 Objetos bsicos del GDI: El Mapa de Bits (Bitmap) 23.1 Tipos de mapas de bits 23.2 Crear un mapa de bits 23.3 Fichero de recursos 23.4 Fichero BMP 23.5 Mostrar un mapa de bits 23.6 Funciones de visualizacin de mapas de bits 23.6.1 BitBlt 23.6.2 StretchBlt 23.6.3 PlgBlt (Slo en Windows NT) 23.6.4 (Slo en Windows NT) 23.7 Cdigos ROP ternarios 23.8 Cdigos ROP cudruples 23.9 Pinceles creados a partir de mapas de bits 23.9.1 PatBlt 23.9.2 ExtFloodFill 23.10 Estructuras de datos 23.10.1 BITMAP 23.11 Modos de estiramiento (stretch modes) 23.12 Mapas de bits de stock 23.13 Ejemplo 21 24 Objetos bsicos del GDI: La Fuente (Font) 24.1 Mostrar un texto simple 24.2 Cambiar el color del texto 24.3 Ejemplo 22 24.4 Crear fuentes personalizadas

24.4.1 Altura y anchura media de carcter 24.4.2 El ngulo de escape 24.4.3 El ngulo de orientacin 24.4.4 Peso 24.4.5 Cursiva 24.4.6 Subrayado 24.4.7 Tachado 24.4.8 Conjunto de caracteres 24.4.9 Precisin de salida 24.4.10 Precisin de recorte 24.4.11 Calidad 24.4.12 Paso y familia 24.4.13 Nombre 24.5 Fuentes de stock 24.6 Alineamientos de texto 24.7 Separacin de caracteres 24.8 Medidas de cadenas 24.9 Justificar texto 24.10 Ejemplo 23 25 Objetos bsicos del GDI: Rectngulos y Regiones 25.1 Rectngulos 25.2 Funciones para trabajar con rectngulos 25.2.1 Asignar rectngulos 25.2.2 Comparaciones de rectngulos 25.2.3 Modificar rectngulos 25.2.4 Operaciones con rectngulos 25.3 Ejemplo 24 25.4 Regiones 25.5 Funciones para regiones 25.5.1 Crear regiones 25.5.2 Combinar regiones 25.5.3 Comparar regiones 25.5.4 Rellenar regiones 25.5.5 Mover una regin 25.5.6 Comprobar posiciones

25.5.7 Destruir regiones 25.6 Ejemplo 25 26 Objetos bsicos del GDI: El camino (Path) 26.1 Crear un camino 26.2 Operaciones con caminos 26.3 Ejemplo 26 27 Objetos bsicos del GDI: El recorte (Clipping) 27.1 Regiones de recorte y el mensaje WM_PAINT 27.2 Funciones relacionadas con el recorte 27.3 Seleccionar regiones de recorte 27.4 Caminos de recorte 27.5 Ejemplo 27 28 Objetos bsicos del GDI: Espacios de coordenadas y transformac 28.1 Definiciones 28.2 Transformaciones 28.2.1 Traslaciones 28.2.2 Cambio de escala 28.2.3 Rotaciones 28.2.4 Cambio de ejes 28.2.5 Reflexiones 28.3 Aplicar transformaciones 28.4 Combinar transformaciones 28.5 Cambios de escala y plumas 28.6 Ejemplo 28 28.7 Ventanas y viewports 28.7.1 Extensiones 28.7.2 Orgenes 28.8 Mapeos

28.9 Modos de mapeo predefinidos 28.10 Modo por defecto 28.11 Transformaciones definidas por el usuario 28.12 Modos grficos y sentido de los arcos 28.13 Otras funciones 28.14 Ejemplo 29 29 Objetos bsicos del GDI: Plumas geomtricas 29.1 Atributos de las plumas geomtricas 29.1.1 Anchura 29.1.2 Estilo de lnea 29.1.3 Color 29.1.4 Patrn 29.1.5 Rayado 29.1.6 Estilo de final (tapn) 29.1.7 Estilo de unin 29.2 Crear una pluma geomtrica 29.3 Seleccionar una pluma geomtrica 29.4 Destruir una pluma geomtrica 30 Objetos bsicos de usuario: El Caret 30.1 Recibir y perder el foco 30.2 Crear y destruir carets 30.3 Mostrar y ocultar carets 30.4 Procesar mensajes WM_PAINT 30.5 Cambiar posicin de un caret 30.6 Cambiar velocidad de parpadeo de un caret 30.7 Ejemplo 31 31 Objetos bsicos del usuario: El icono 31.1 Punto activo 31.2 Tamaos 31.3 Asociar iconos a una aplicacin 31.4 Tipos

31.5 Iconos en ficheros de recursos 31.6 Iconos en controles estticos 31.7 Mostrar iconos 31.8 Destruccin de iconos 31.9 Ejemplo 32 32 Objetos bsicos del usuario: El cursor 32.1 Cursor de clase 32.2 Cursores de recursos 32.3 Cursores estndar 32.4 Similitud entre iconos y cursores 32.5 El punto activo (Hot Spot) 32.6 Crear cursores 32.7 Posicin del cursor 32.8 Apariencia 32.9 Modificar el cursor de clase 32.10 El mensaje WM_SETCURSOR 32.11 Ocultar y mostrar 32.12 Confinar el cursor 32.13 Destruccin de cursores 32.14 Ejemplo 33 33 El ratn 33.1 Capturar el ratn 33.2 Configuracin 33.3 Mensajes 33.3.1 Mensajes del rea de cliente 33.3.2 Mensajes del rea de no cliente 33.3.3 Mensaje WM_NCHITTEST 33.3.4 Mensaje WM_MOUSEACTIVATE 33.4 Otros mensajes de ratn 33.4.1 Mensaje WM_MOUSEWHEEL (Windows NT) 33.5 Trazar eventos del ratn (Windows NT)

33.5.1 Mensaje WM_MOUSELEAVE (Windows NT) 33.5.2 Mensaje WM_MOUSEHOVER (Windows NT) 33.6 Ejemplo 34 33.7 Arrastrar objetos 33.8 Ejemplo 35 34 El teclado 34.1 El Foco del teclado 34.2 Ventanas inhibidas 34.3 Ejemplo 36 34.4 Mensajes de pulsacin de teclas 34.5 Nombres de teclas 34.6 El bucle de mensajes 34.7 Ejemplo 37 34.8 Mensajes de carcter 34.8.1 Teclas muertas 34.9 Estado de teclas 34.10 Ejemplo 38 34.11 Hot keys 34.12 Ejemplo 39 34.13 Cdigos de teclas virtuales 35 Cadenas 35.1 Recursos de cadenas 35.1.1 Fichero de recursos 35.1.2 Cargar cadenas desde recursos 35.2 Funciones para cadenas 35.3 Ejemplo 40 36 Aceleradores 36.1 Recursos de aceleradores

36.1.1 Fichero de recursos 36.1.2 Cargar aceleradores desde recursos 36.2 Bucle de mensajes para usar aceleradores 36.3 Crear tablas de aceleradores sin usar recursos 36.4 Combinar aceleradores y mens 36.5 Aceleradores globales 36.6 Diferencia entre acelerador y men 36.7 Ejemplo 41 37 Mens 2 37.1 Marcas en mens 37.1.1 Mens como checkboxes 37.1.2 Mens como radiobuttons 37.2 Ejemplo 42 37.3 Inhibir y oscurecer tems 37.4 Ejemplo 43 37.5 Ms sobre ficheros de recursos 37.5.1 Sentencia MENUITEM y POPUP 37.5.2 Detalles sobre cadenas de tems 37.5.3 Sentencia MENUEX 37.5.4 Items marcados y no marcados 37.5.5 Items activos, inactivos u oscurecidos 37.5.6 Separadores y lneas de ruptura 37.5.7 Cargar recursos 37.6 tems por defecto 37.7 Ejemplo 44 37.8 Mens flotantes o contextuales 37.9 Ejemplo 45 37.10 Acceso por teclado 37.10.1 Mnemnicos 37.10.2 Aceceso de teclado estndar 37.10.3 Aceleradores 37.11 Modificar mens 37.12 El men de sistema

37.12.1 Modificar el men de sistema 37.13 Ejemplo 46 37.14 Destruccin de mens 37.15 Mensajes de men 37.16 Mapas de bits en tems de men 37.16.1 Modificar mapas de bits de check 37.16.2 Items de mapas de bits 37.17 Ejemplo 47 38 La memoria 38.1 Memoria virtual 38.2 Un poco de historia 38.2.1 Memoria local y global 38.2.2 Otros atributos de la memoria en Windows 38.2.3 Objetos mviles y fijos 38.2.4 Objetos descartables y no descartables 38.2.5 Funciones clsicas para manejo de memoria 38.2.6 Desventajas de este modelo de memoria 38.3 Funciones para manejo de memoria virtual 38.3.1 Reservar direcciones de memoria virtual 38.3.2 Liberar direcciones de memoria virtual 38.3.3 Bloquear pginas de memoria asignada 38.3.4 Establecer atributos de proteccin de acceso 38.3.5 Obtener informacin sobre pginas de memoria 38.4 Ejemplo 48 39 Control edit avanzado 39.1 Insertar controles edit durante la ejecucin

39.2 Cambiar la fuente de un control edit 39.3 Cambiar los colores de un control edit 39.4 Ejemplo 49 39.5 Contoles edit de slo lectura 39.6 Ejemplo 50 39.7 Leer contraseas 39.8 Ejemplo 51 39.9 Maysculas y minsculas 39.10 Ejemplo 52 39.11 Mensajes de notificacin 39.11.1 Modificacin 39.11.2 Actualizacin 39.11.3 Falta espacio 39.11.4 Desplazamiento horizontal y vertical 39.11.5 Prdida y recuperacin de foco 39.11.6 Texto mximo 39.12 El buffer de texto 39.13 Controles multilnea 39.13.1 Iniciar controles multilnea 39.13.2 Mensajes para controles multilnea 39.14 Ejemplo 53 39.15 Operaciones sobre selecciones de texto 39.16 Deshacer cambios (undo) 39.17 Modificacin del texto 39.18 Mrgenes y tabuladores 39.19 Desplazar texto 39.20 Ejemplo 54 39.21 Caracteres y posiciones 39.22 Ejemplo 55 40 Control list box avanzado 40.1 Insertar controles list box durante la ejecucin 40.2 Cambiar la fuente de un control list box 40.3 Cambiar los colores de un control list box 40.4 Ejemplo 56 40.5 Mensajes de notificacin

40.5.1 Doble clic 40.5.2 Falta espacio 40.5.3 Prdida y recuperacin de foco 40.5.4 Seleccin y deseleccin 40.6 Mensajes ms comunes 40.7 Ejemplo 57 40.8 El dato del tem 40.9 Ejemplo 58 40.10 Funciones para ficheros y directorios 40.11 Ejemplo 59 40.12 Listbox de seleccin sencilla y mltiple 40.12.1 Selecciones 40.12.2 Mensajes especiales para list box de seleccin extendida 40.13 Ejemplo 60 40.14 List box sin seleccin 40.15 List box multicolumna 40.16 Ejemplo 61 40.17 Paradas de tabulacin 40.18 Ejemplo 62 40.19 Actualizaciones de gran nmero de tems 40.19.1 Optimizar la memoria 40.19.2 Optimizar el tiempo 40.20 Ejemplo 63 40.21 Responder al teclado 40.22 Ejemplo 64 40.23 Aspectos grficos del list box 40.23.1 Ajustar la anchura de un list box 40.23.2 Ajustar la altura de los tems 40.23.3 Items y coordenadas 40.24 Ejemplo 65 40.25 Localizaciones 40.26 Ejemplo 66 40.27 Otros estilos 40.28 List box a medida (owner-draw)

40.29 Estilos owner-draw para list box 40.29.1 List box owner-draw de altura fija 40.29.2 List box owner-draw de altura variable 40.29.3 Dibujar cada tem 40.29.4 El mensaje WM_DELETEITEM 40.30 Ejemplo 67 40.31 Otros mensajes para list box con estilos owner-draw 40.32 Definicin del orden 41 Control button avanzado 41.1 Insertar botones durante la ejecucin 41.2 Cambiar fuente 41.3 Cambiar colores 41.4 Modificar el bucle de mensajes 41.5 Botones con iconos o mapas de bits 41.6 Otros estilos para botones 41.6.1 Alineacin de contenidos 41.6.2 Check box y Radio buttons 41.7 Ejemplo 68 41.8 Mensajes de notificacin 41.8.1 Seleccin 41.8.2 Doble clic 41.8.3 Prdida y recuperacin de foco 41.8.4 Inhibir mensajes de notificacin 41.9 Estilos de cada tipo de botn 41.9.1 Botones pulsables 41.9.2 Check boxes 41.9.3 Radio buttons 41.9.4 Cajas de grupo 41.9.5 Botones owner-draw 41.10 Estados de un botn 41.10.1 Seleccin de un botn

41.10.2 Cambios de estado 41.11 Funciones para controles botn 41.11.1 Funciones propias de controles botn 41.12 Modificar el estilo de un botn 41.13 Botones owner-draw 41.14 Ejemplo 69 42 Control esttico avanzado 42.1 Insertar controles estticos durante la ejecucin 42.2 Cambiar fuente 42.3 Cambiar colores 42.4 Estilos estticos grficos 42.4.1 Marcos 42.4.2 Rectngulos 42.4.3 Ranurados 42.4.4 Ejemplos 42.4.5 Ms sobre los ranurados 42.5 Estilos estticos de texto 42.6 Imgenes 42.6.1 Mensajes para asignar imgenes 42.6.2 Modificadores de estilo 42.7 Modificador de hundido 42.8 Mensajes de notificacin 42.9 Controles estticos owner-draw 42.10 Ejemplo 70 43 Control combo box avanzado 43.1 Tipos de combo boxes 43.2 Insertar controles combo box durante la ejecucin 43.3 Cambiar la fuente de un control combo box 43.4 Cambiar colores en combo box 43.5 Mensajes de notificacin

43.5.1 Cambio en seleccin de lista 43.5.2 Validar seleccin 43.5.3 Despliegue de lista 43.5.4 Doble clic 43.5.5 Falta espacio 43.5.6 Modificacin 43.5.7 Actualizacin 43.5.8 Prdida y recuperacin de foco 43.6 Otros estilos para combo box 43.6.1 Estilos para la parte de edicin 43.6.2 Estilos para la lista 43.7 Ejemplo 71 43.8 Mensajes correspondientes a la lista 43.8.1 Aadir tems 43.8.2 Recuperar informacin 43.8.3 Cambiar la seleccin 43.8.4 Buscar tems 43.8.5 Borrar tems 43.8.6 Otros mensajes 43.9 Ejemplo 72 43.10 El dato del tem 43.11 Interfaces de usuario 43.12 Funciones para ficheros y directorios 43.12.1 Juegos de caracteres 43.12.2 Procesar CBN_CLOSEUP 43.13 Seleccin actual 43.14 Ejemplo 73 43.15 El control de edicin 43.16 Actualizaciones de gran nmero de tems 43.16.1 Optimizar la memoria 43.16.2 Optimizar el tiempo 43.17 Aspectos grficos del combo box

43.17.1 Ajustar la anchura de un combo box 43.17.2 Ajustar la altura de los tems 43.18 Localizaciones 43.19 Combo boxes owner draw 43.19.1 Combo box owner-draw de altura fija 43.19.2 Combo box owner-draw de altura variable 43.19.3 Dibujar cada tem 43.20 Otros mensajes para combo box con estilos owner-draw 43.20.1 El mensaje WM_DELETEITEM 43.21 Dimensiones de la lista desplegable 43.22 Definicin del orden 43.23 Ejemplo 74 44 Control scrollbar avanzado 44.1 Controles de barra de desplazamiento y barras estndar 44.2 Insertar controles scrollbar durante la ejecucin 44.3 Cambiar colores 44.4 Estilos de scrollbar 44.4.1 Estilos de orientacin 44.4.2 Alineamiento con los bordes 44.4.3 Opciones para cajas de tamao 44.4.4 Alineamiento de cajas de tamao 44.5 Mostrar u ocultar barras de desplazamiento 44.6 Deshabilitar o habilitar un control de barra de desplazamiento 44.7 Deshabilitar o habilitar flechas 44.7.1 Usando funciones 44.7.2 Usando mensajes 44.8 Mensajes de barras de desplazamiento 44.9 Respuesta al teclado 44.10 Ejemplo 75

44.11 Desplazar contenido de ventanas 44.12 Colores y medidas 44.12.1 Valores de medidas del sistema 44.13 Otros mensajes 44.14 Ejemplo 76 A Glosario

IntroduccinRequisitos previosPara el presente curso supondr que ests familiarizado con la programacin en C y C++ y tambin con las aplicaciones y el entorno Windows, al menos al nivel de usuario. Sin embargo, no se requerirn muchos ms conocimientos. El curso pretende ser una explicacin de la forma en que se realizan los programas en Windows usando el API. Las explicaciones de las funciones y los mensajes del API son meras traducciones del fichero de ayuda de WIN32 de Microsoft, y slo se incluyen como complemento. Para empezar, vamos a ponernos en antecedentes. Veamos primero algunas caractersticas especiales de la programacin en Windows.

Independencia de la mquinaLos programas Windows son independientes de la mquina en la que se ejecutan (o al menos deberan serlo), el acceso a los dispositivos fsicos se hace a travs de interfaces, y nunca se accede directamente a ellos. Esta es una de las principales ventajas para el programador, ya que no hay que preocuparse por el modelo de tarjeta grfica o de impresora, la aplicacin funcionar con todas, y ser el sistema operativo el que se encargue de que as sea.

RecursosUn concepto importante es el de recurso. Desde el punto de vista de Windows, un recurso es todo aquello que puede ser usado por una o varias aplicaciones. Existen recursos fsicos, que son los dispositivos que componen el ordenador, como la memoria, la impresora, el teclado o el ratn y recursos virtuales o lgicos, como los grficos, los iconos o las cadenas de caracteres. Por ejemplo, si nuestra aplicacin requiere el uso de un puerto serie, primero debe averiguar si est disponible, es decir, si existe y si no lo est usando otra aplicacin; y despus lo reservar para su uso. Esto es necesario porque este tipo de recurso no puede ser compartido. Lo mismo pasa con la memoria o con la tarjeta de sonido, aunque son casos diferentes. Por ejemplo, la memoria puede ser compartida, pero de una forma general, cada porcin de memoria no puede compartirse, (al menos en los casos normales, veremos que es posible hacer aplicaciones con memoria compartida), y se trata de un recurso finito. Las tarjetas de sonido, dependiendo del modelo, podrn o no compartirse por varias aplicaciones. Otros recursos como el ratn y el teclado tambin se comparten, pero se asigna su uso automticamente a la aplicacin activa, a la que normalmente nos referiremos como la que tiene el "foco", es decir, la que mantiene contacto con el usuario.

Desde nuestro punto de vista, como programadores, tambin consideramos recursos varios componentes como los mens, los iconos, los cuadros de dilogo, las cadenas de caracteres, los mapas de bits, los cursores, etc. En sus programas, el Windows almacena separados el cdigo y los recursos, dentro del mismo fichero, y estos ltimos pueden ser editados por separado, permitiendo por ejemplo, hacer versiones de los programas en distintos idiomas sin tener acceso a los ficheros fuente de la aplicacin.

VentanasLa forma en que se presentan las aplicaciones Windows (al menos las interactivas) ante el usuario, es la ventana. Supongo que todos sabemos qu es una ventana: un rea rectangular de la pantalla que se usa de interfaz entre la aplicacin y el usuario. Cada aplicacin tiene al menos una ventana, la ventana principal, y todas las comunicaciones entre usuario y aplicacin se canalizan a travs de una ventana. Cada ventana comparte el espacio de la pantalla con otras ventanas, incluso de otras aplicaciones, aunque slo una puede estar activa, es decir, slo una puede recibir informacin del usuario.

EventosLos programas en Windows estn orientados a eventos, esto significa que normalmente los programas estn esperando a que se produzca un acontecimiento que les incumba, y mientras tanto permanecen aletargados o dormidos. Un evento puede ser por ejemplo, el movimiento del ratn, la activacin de un men, la llegada de informacin desde el puerto serie, una pulsacin de una tecla... Esto es as porque Windows es un sistema operativo multitarea, y el tiempo del microprocesador ha de repartirse entre todos los programas que se estn ejecutando. Si los programas fueran secuenciales puros, esto no sera posible, ya que hasta que una aplicacin finalizara, el sistema no podra atender al resto.

Ejemplo de programa secuencial:

Ejemplo de programa por eventos:

ProyectosDebido a la complejidad de los programas Windows, normalmente los dividiremos en varios ficheros fuente, que compilaremos por separado y enlazaremos juntos. Cada compilador puede tener diferencias, ms o menos grandes, a la hora de trabajar con proyectos. Sin embargo creo que no deberas tener grandes dificultades para adaptarte a cada uno de ellos. En el presente curso trabajaremos con el compilador de "Bloodshed", que es pblico y gratuito, y puede descargarse de Internet en la siguiente URL: http://www.bloodshed.net/. Para crear un proyecto Windows usando este compilador elegiremos el men "File/New Project".

Se abrir un cuadro de dilogo donde podremos elegir el tipo de proyecto. Elegiremos "Windows Application" y "C++ Project". A continuacin pulsamos "Aceptar". El compilador crea un proyecto con un fichero C++, con el esqueleto de una aplicacin para una ventana, a partir de ah empieza nuestro trabajo.

ConvencionesEn parte para que no te resulte muy difcil adaptarte a la terminologa de Windows, y a la documentacin existente, y en parte para seguir mi propia costumbre, en la mayora de los casos me referir a componentes y propiedades de Windows con sus nombres en ingls. Por ejemplo, hablaremos de "button", "check box", "radio button", "list box", "combo box" o "property sheet", aunque algunas veces traduzca sus nombre a espaol, por ejemplo, "dialog box" se nombrar a menudo como "cuadro de dilogo". Adems hablaremos a menudo de ventanas "overlapped" o superponibles, que son las ventanas corrientes. Para el trmino "pop-up" he desistido de buscar una traduccin. Tambin se usaran a menudo, con relacin a "check boxes", trminos ingleses como checked, unchecked o grayed, en lugar de marcado, no marcado o gris. Owner-draw, es un estilo que indica que una ventana o control no es la encargada de actualizarse en pantalla, esa responsabilidad es transferida a la ventana duea del control o ventana. Para "bitmap" se usar a menudo la expresin "mapa de bits".

ControlesLos controles son la forma en que las aplicaciones Windows intercambian datos con el usuario. Normalmente se usan dentro de los cuadros de dilogo, pero en realidad pueden usarse en cualquier ventana. Existen bastantes, y los iremos viendo poco a poco, al mismo tiempo que aprendemos a manejarlos. Los ms importantes y conocidos son:q q q q q

q

control estatic: son etiquetas, marcos, iconos o dibujos. control edit: permiten que el usuario introduzca datos alfanumricos en la aplicacin. control list box: el usuario puede escoger entre varias opciones de una lista. control combo box: es una combinacin entre un edit y un list box. control scroll bar: barras de desplazamiento, para la introduccin de valores entre mrgenes definidos. control button: realizan acciones o comandos, de button de derivan otros dos controles muy comunes: r control check box: permite leer variables de dos estados "checked" o "unchecked"

r

control radio button: se usa en grupos, dentro de cada grupo slo uno puede ser activado.

Captulo 1 Componentes de una ventanaVeamos ahora los elementos que componen una ventana, aunque ms adelante veremos que no todos tienen por qu estar presentes en todas las ventanas.

El borde de la ventanaHay varios tipos, dependiendo de que estn o no activas las opciones de cambiar el tamao de la ventana. Se trata de un rea estrecha alrededor de la ventana que permite cambiar su tamao (1).

Barra de ttuloZona en la parte superior de la ventana que contiene el icono y el ttulo de la ventana, esta zona tambin se usa para mover la ventana a travs de la pantalla, y mediante doble clic, para cambiar entre el modo maximizado y tamao normal (2).

Caja de minimizarPequea rea cuadrada situada en la parte derecha de la barra de ttulo que sirve para disminuir el tamao de la ventana. Antes de la aparicin del Windows 95 la ventana se converta a su forma icnica, pero desde la aparicin del Windows 95 los iconos desaparecieron, la ventana se oculta y slo permanece un botn en la barra de estado (3).

Caja de maximizarPequea rea cuadrada situada en la parte derecha de la barra de ttulo que sirve para agrandar la ventana para que ocupe toda la pantalla. Cuando la ventana est maximizada, se sustituye por la caja de restaurar (4).

Caja de cerrarPequea rea cuadrada situada en la parte derecha de la barra de ttulo que sirve para cerrar la ventana. (5)

Caja de control de menPequea rea cuadrada situada en la parte izquierda de la barra de ttulo, normalmente contiene el icono de la ventana, y sirve para desplegar el men del sistema (6).

MenO men del sistema. Se trata de una ventana especial que contiene las funciones comunes a todas las ventanas, tambin accesibles desde las cajas y el borde, como minimizar, restaurar, maximizar, mover, cambiar tamao y cerrar. Este men se despliega al pulsar sobre la caja de control de men.

Barra de menZona situada debajo de la barra de ttulo, contiene los mens de la aplicacin (7).

Barra de scroll horizontalBarra situada en la parte inferior de la ventana, permite desplazar horizontalmente la vista del rea de cliente (8).

Barra de scroll verticalBarra situada en la parte derecha de la ventana, permite desplazar verticalmente la vista del rea de cliente (9).

El rea de clienteEs la zona donde el programador sita los controles, y los datos para el usuario. En general es toda la superficie de la ventana lo que no est ocupada por las zonas anteriores (10).

Captulo 2 Notacin HngaraLa notacin hngara es un sistema usado normalmente para crear los nombres de variables, tipos y estructuras cuando se programa en Windows. Es el sistema usado en la programacin del sistema operativo, y tambin por la mayora de los programadores. A veces tambin usaremos este sistema en algunos ejemplos de este curso, pero sobre todo, nos ayudar a interpretar el tipo bsico al que pertenece cada estructura, miembro, o tipo definido. Consiste en prefijos en minsculas que se aaden a los nombres de las variables, y que indican su tipo; en el caso de tipos definidos, las letras del prefijo estarn en mayscula. El resto del nombre indica, lo ms claramente posible, la funcin que realiza la variable o tipo. Prefijo Significado b c dw f h l lp lpfn lpsz n p pt rgb sz u w Booleano Carcter (un byte) Entero largo de 32 bits sin signo (DOBLE WORD) Flags empaquetados en un entero de 16 bits Manipulador de 16 bits (HANDLE) Entero largo de 32 bits Puntero a entero largo de 32 bits Puntero largo a una funcin que devuelve un entero Puntero largo a una cadena terminada con cero Entero de 16 bits Puntero a entero de 16 bits Coordenadas (x, y) empaquetadas en un entero de 32 bits Valor de color RGB empaquetado en un entero de 32 bits Cadena terminada en cero Sin signo (unsigned) Entero corto de 16 bits sin signo (WORD)

EjemplosnContador: la variable es un entero que se usar como contador. szNombre: una cadena terminada con cero que almacena un nombre. bRespuesta: una variable booleana que almacena una respuesta. Ejemplos de tipos definidos por el API de Windows:

UINT: entero sin signo. Windows redefine los enteros para asegurar que el tamao en bits es siempre el mismo para todas las variables del API. LRESULT: entero largo usado como valor de retorno. WPARAM: entero corto de 16 bits usado como parmetro. LPARAM: entero largo de 32 bits usado como parmetro. LPSTR: puntero largo a una cadena de caracteres. En el API de 32 bits no existen distinciones entre punteros largos y cortos, pero la nomenclatura se conserva por compatibilidad. LPCREATESTRUCT: puntero a una estructura CREATESTRUCT.

Captulo 3 Estructura de un programa Windows GUIHay algunas diferencias entre la estructura de un programa C/C++ normal, y la correspondiente a un programa Windows GUI. Algunas de estas diferencias se deben a que los programas GUI ests basados en mensajes, otros son sencillamente debidos a que siempre hay un determinado nmero de tareas que hay que realizar.

// Ficheros include: #include // Prototipos: LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM); // Funcin de entrada: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { // Declaracin: // Inicializacin: // Bucle de mensajes: return Message.wParam; } // Definicin de funciones:

CabecerasLo primero es lo primero, para poder usar las funciones del API de Windows hay que incluir al menos un fichero de cabecera, pero generalmente no bastar con uno. El fichero lo que hace es incluir la mayora de los ficheros de cabecera corrientes en aplicaciones GUI, pero podemos incluir slo los que necesitemos, siempre que sepamos cuales son. Por ejemplo, la funcin WinMain est declarada en el fichero de cabecera winbase.h. Generalmente esto resultar incmodo, ya que para cada nueva funcin, mensaje o estructura tendremos que comprobar, y si es necesario, incluir nuevos ficheros. Es mejor usar windows.h directamente.

PrototiposCada tipo (o clase) de ventana que usemos en nuestro programa (normalmente slo ser una), o cada cuadro de dilogo (de estos puede haber muchos), necesitar un procedimiento propio, que

deberemos declarar y definir. Siguiendo la estructura de un programa C, esta es la zona normal de declaracin de prototipos.

Funcin de entrada, WinMainLa funcin de entrada de un programa Windows es "WinMain", en lugar de la conocida "main". Normalmente, la definicin de esta funcin cambia muy poco de una aplicaciones a otras. Se divide en tres partes claramente diferenciadas: declaracin, inicializacin y bucle de mensajes.

Parmetros de entrada de "WinMain"int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)

La funcin WinMain tiene cuatro parmetros de entrada:q

q

q q

hInstance es un manipulador para la instancia del programa que estamos ejecutando. Cada vez que se ejecuta una aplicacin, Windows crea una Instancia para ella, y le pasa un manipulador de dicha instancia a la aplicacin. hPrevInstance es un manipulador a instancias previas de la misma aplicacin. Como Windows es multitarea, pueden existir varias versiones de la misma aplicacin ejecutndose, varias instancias. En Windows 3.1, este parmetro nos serva para saber si nuestra aplicacin ya se estaba ejecutando, y de ese modo se podan compartir los datos comunes a todas las instancias. Pero eso era antes, ya que en Win32 usa un segmento distinto para cada instancia y este parmetro es siempre NULL, slo se conserva por motivos de compatibilidad. lpszCmdParam, esta cadena contiene los argumentos de entrada del comando de lnea. nCmdShow, este parmetro especifica cmo se mostrar la ventana. Para ver sus posibles valores consultar valores de ncmdshow. Se recomienda no usar este parmetro en la funcin ShowWindow la primera vez que se sta es llamada. En su lugar debe usarse el valor SW_SHOWDEFAULT.

Funcin WinMain tpicaint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { /* Declaracin: */ HWND hwnd; MSG mensaje; WNDCLASSEX wincl; /* Inicializacin: */ /* Estructura de la ventana */ wincl.hInstance = hInstance;

wincl.lpszClassName = "NUESTRA_CLASE"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof(WNDCLASSEX); /* Usar icono y puntero por defecto */ wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor(NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; hwnd = CreateWindowEx( 0, "NUESTRA_CLASE", "Ejemplo 001", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hThisInstance, NULL ); ShowWindow(hwnd, SW_SHOWDEFAULT); /* Bucle de mensajes: */ while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } return mensaje.wParam; }

DeclaracinEn la primera zona declararemos las variables que necesitamos para nuestra funcin WinMain, que como mnimo sern tres:q

q

HWND hWnd, un manipulador para la ventana principal de la aplicacin. Ya sabemos que nuestra aplicacin necesitar al menos una ventana. MSG Message, una variable para manipular los mensajes que lleguen a nuestra aplicacin.

q

WNDCLASSEX wincl, una estructura que se usar para registrar la clase particular de ventana que usaremos en nuestra aplicacin. Existe otra estructura para registrar clases que se usaba antiguamente, pero que ha sido desplazada por esta nueva versin, se trata de WNDCLASS.

InicializacinEsta zona se encarga de registrar la clase o clases de ventana, crear la ventana y visualizarla en pantalla. Para registrar la clase primero hay que rellenar adecuadamente la estructura WNDCLASSEX, que define algunas caractersticas que sern comunes a todas las ventanas de una misma clase, como color de fondo, icono, men por defecto, el procedimiento de ventana, etc. Despus hay que llamar a la funcin RegisterClassEx. En el caso de usar una estructura WNDCLASS se debe registrar la clase usando la funcin RegisterClass. A continuacin se crea la ventana usando la funcin CreateWindowEx, la funcin CreateWindow ha cado prcticamente en desuso. Cualquiera de estas dos funciones nos devuelve un manipulador de ventana que podemos necesitar en otras funciones, sin ir ms lejos, la siguiente. Pero esto no muestra la ventana en la pantalla. Para que la ventana sea visible hay que llamar a la funcin ShowWindow. La primera vez que se llama a sta funcin, despus de crear la ventana, se puede usar el parmetro nCmdShow de WinMain como parmetro o mejor an, como se recomienda por Windows, el valor SW_SHOWDEFAULT.

Bucle de mensajesEste es el ncleo de la aplicacin, como se ve en el ejemplo el programa permanece en este bucle mientras la funcin GetMessage retorne con un valor TRUE.

while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); }

Este es el bucle de mensajes recomendable, aunque no sea el que se usa habitualmente. La razn es que la funcin GetMessage puede retornar tres valores: TRUE, FALSE -1. El valor -1 indica un error, as que en este caso se debera abandonar el bucle. El bucle de mensajes que encontraremos habitualmente es este:

while(GetMessage(&mensajee, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); }

NOTA: El problema con este bucle es que si GetMessage regresa con un valor -1, que indica un error, la condicin del "while" se considera verdadera, y el bucle contina. Si el error es permanente, el programa jams terminar. La funcin TranslateMessage se usa para traducir los mensajes de teclas virtuales a mensajes de carcter. Veremos esto con ms detalle en el captulo dedicado al teclado (cap. 34). Los mensajes traducidos se reenvan a la lista de mensajes del proceso, y se recuperarn con las siguientes llamadas a GetMessage. La funcin DispatchMessage enva el mensaje al procedimiento de ventana, donde ser tratado adecuadamente. El prximo captulo est dedicado al procedimiento de ventana, y al final de l estaremos en disposicin de crear nuestro primer programa Windows.

Definicin de funcionesEn esta parte definiremos, entre otras cosas, los procedimientos de ventana, que se encargan de procesar los mensajes que lleguen a cada ventana.

Captulo 4 El procedimiento de ventanaCada ventana tiene una funcin asociada, esta funcin se conoce como procedimiento de ventana, y es la encargada de procesar adecuadamente todos los mensajes enviados a una determinada clase de ventana. Es la responsable de todo lo relativo al aspecto y al comportamiento de una ventana. Normalmente, estas funciones estn basadas en una estructura "switch" donde cada "case" corresponde aun determinado tipo de mensaje.

SintaxisLRESULT CALLBACK WindowProcedure( HWND hwnd, // Manipulador de ventana UINT msg, // Mensaje WPARAM wParam, // Parmetro palabra, vara LPARAM lParam // Parmetro doble palabra, vara );

q q q q

hwnd es el manipulador de la ventana a la que est destinado el mensaje. msg es el cdigo del mensaje. wParam es el parmetro de tipo palabra asociado al mensaje. lParam es el parmetro de tipo doble palabra asociado al mensaje.

Podemos considerar este prototipo como una plantilla para crear nuestros propios procedimientos de ventana. El nombre de la funcin puede cambiar, pero el valor de retorno y los parmetros deben ser los mismos. El miembro lpfnWndProc de la estructura WNDCLASS es un puntero a una funcin de este tipo, esa funcin es la que se encargar de procesar todos los mensajes para esa clase de ventana. Cuando registremos nuestra clase de ventana, tendremos que asignar a ese miembro el puntero a nuestro procedimiento de ventana. Para ms detalles sobre la funcin de procedimiento de ventana, consultar WindowProc.

Prototipo de procedimiento de ventanaLRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);

Implementacin de procedimiento de ventana simple/* Esta funcin es llamada por la funcin del API DispatchMessage() */

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) /* manipulador del mensaje */ { case WM_DESTROY: PostQuitMessage(0); /* enva un mensaje WM_QUIT a la cola de mensajes */ break; default: /* para los mensajes de los que no nos ocupamos */ return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; }

En general, habr tantos procedimientos de ventana como programas diferentes y todos sern distintos, pero tambin tendrn algo en comn: todos ellos procesarn los mensajes que lleguen a una clase de ventana. En este ejemplo slo procesamos un tipo de mensaje, se trata de WM_DESTROY que es el mensaje que se enva a una ventana cuando se recibe un comando de cerrar, ya sea por men o mediante el icono de aspa en la esquina superior derecha de la ventana. Este mensaje slo sirve para informar a la aplicacin de que el usuario tiene la intencin de abandonar la aplicacin, y le da una oportunidad de dejar las cosas en su sitio: cerrar ficheros, liberar memoria, guardar variables, etc. Incluso, la aplicacin puede decidir que an no es el momento adecuado para abandonar la aplicacin. En el caso del ejemplo, efectivamente cierra la aplicacin, y lo hace envindole un mensaje WM_QUIT, mediante la funcin PostQuitMessage. El resto de los mensajes se procesan en el caso "default", y simplemente se cede su tratamiento a la funcin del API que hace el proceso por defecto para cada mensaje, DefWindowProc. Este es el camino que sigue el mensaje WM_QUIT cuando llega, ya que el proceso por defecto para este mensaje es cerrar la aplicacin. En posteriores captulos veremos como se complica paulatinamente esta funcin, aadiendo ms y ms mensajes.

Primer ejemplo de programa WindowsYa estamos en condiciones de crear nuestro primer programa Windows, que slo mostrar una ventana en pantalla. Nombre Fichero Fecha Tamao Descarga

Ejemplo 1

win001.zip

2004-01-18

1968 bytes

Captulo 5 Mens 1Ahora que ya sabemos hacer el esqueleto de una aplicacin Windows, veamos el primer medio para comunicarnos con ella. Supongo que todos sabemos lo que es un men: se trata de una ventana un tanto especial, del tipo pop-up, que contiene una lista de comandos u opciones entre las cuales el usuario puede elegir. Cuando se usan en una aplicacin, normalmente se agrupan varios mens bajo una barra horizontal, (que no es otra cosa que un men), dividida en varias zonas o tems. Cada tem de un men, (salvo los separadores y aquellos que despliegan nuevos mens), tiene asociado un identificador. El valor de ese identificador se usar por la aplicacin para saber qu opcin se activ por el usuario, y decidir las acciones a tomar en consecuencia. Existen varias formas de aadir un men a una ventana, veremos cada una de ellas por separado. Tambin es posible desactivar o inhibir algunas opciones para que no estn disponibles para el usuario.

Usando las funciones para insercin tem a temEste es el sistema ms rudimentario, pero como ya veremos en el futuro, en ocasiones puede ser muy til. Empezaremos viendo este sistema porque ilustra mucho mejor la estructura de los mens. Tomemos el ejemplo del captulo anterior y definamos algunas constantes:

#define CM_PRUEBA 100 #define CM_SALIR 101

Y aadamos la declaracin de una funcin en la zona de prototipos:

void InsertarMenu(HWND);

Al final del programa aadimos la definicin de esta funcin:

void InsertarMenu(HWND hWnd) { HMENU hMenu1, hMenu2;

hMenu1 = CreateMenu(); /* Manipulador de la barra de men */ hMenu2 = CreateMenu(); /* Manipulador para el primer men pop-up */ AppendMenu(hMenu2, MF_STRING, CM_PRUEBA, "&Prueba"); /* 1 tem */ AppendMenu(hMenu2, MF_SEPARATOR, 0, NULL); /* 2 tem (separador) */ AppendMenu(hMenu2, MF_STRING, CM_SALIR, "&Salir"); /* 3 tem */ /* Insercin del men pop-up */ AppendMenu(hMenu1, MF_STRING | MF_POPUP, (UINT)hMenu2, "&Principal"); SetMenu (hWnd, hMenu1); /* Asigna el men a la ventana hWnd */ }

Y por ltimo, slo nos queda llamar a nuestra funcin, insertaremos sta llamada justo antes de visualizar la ventana.

... InsertarMenu(hWnd); ShowWindow(hWnd, SW_SHOWDEFAULT); ...

Veamos cmo funciona "InsertarMenu". La primera novedad son las variables del tipo HMENU. HMENU es un tipo de manipulador especial para mens. Necesitamos dos variables de este tipo, una para manipular la barra de men, hMenu1. La otra para manipular cada uno de los mens pop-up, en este caso slo uno, hMenu2. De momento haremos una barra de men con un nico elemento que ser un men pop-up. Despus veremos como implementar mens ms complejos. Para crear un men usaremos la funcin CreateMenu, que crea un men vaco. Para ir aadiendo tems a cada men usaremos la funcin AppendMenu. Esta funcin tiene varios argumentos: El primero es el men donde queremos insertar el nuevo tem. El segundo son las opciones o atributos del nuevo tem, por ejemplo MF_STRING, indica que se trata de un tem de tipo texto, MF_SEPARATOR, es un tem separador y MF_POPUP, indica que se trata de un men que desplegar un nuevo men pop-up. El siguiente parmetro puede tener distintos significados:q

q

Puede ser un identificador de comando, este identificador se usar para comunicar a la aplicacin si el usuario selecion un determinado tem. Un manipulador de men, si el tem tiene el flag MF_POPUP, en este caso hay que hacer

q

un casting a (UINT). O tambin puede ser cero, si se trata de un separador.

El ltimo parmetro es el texto del tem, cuando se ha especificado el flag MF_STRING, ms adelante veremos que los tems pueden ser tambin bitmaps. Normalmente se trata de una cadena de texto. Pero hay una peculiaridad interesante, para indicar la tecla que activa un determinado tem de un men se muestra la letra correspondiente subrayada. Esto se consigue insertando un '&' justo antes de la letra que se quiere usar como atajo, por ejemplo, en el tem "&Prueba" esta letra ser la 'P'. Por ltimo SetMenu, asigna un men a una ventana determinada. El primer parmetro es el manipulador de la ventana, y el segundo el del men. Prueba estas funciones y juega un rato con ellas. A continuacin veremos cmo hacer que nuestra aplicacin responda a los mensajes del men.

Uso bsico de MessageBoxAntes de aprender a visualizar texto en la ventana, usaremos un mecanismo ms simple para informar al usuario de cualquier cosa que pase en nuestra aplicacin. Este mecanismo no es otro que el cuadro de mensaje (message box), que consiste en una pequea ventana con un mensaje para el usuario y uno o varios botones, segn el tipo de cuadro de mensaje que usemos. En nuestros primeros ejemplos, el cuadro de mensaje slo incluir el botn de "Aceptar". Para visualizar un cuadro de mensaje simple, usaremos la funcin MessageBox. En nuestros ejemplos bastar con la siguiente forma:

MessageBox(hWnd, "Texto de mensaje", "Texto de ttulo", MB_OK);

Esto mostrar un pequeo cuadro de dilogo con el texto y el ttulo especificados y un botn de "Aceptar". El cuadro se cerrar al pulsar el botn o al pulsar la tecla de Retorno.

Respondiendo a los mensajes del menLas activaciones de los mens se reciben mediante un mensaje WM_COMMAND. Para procesar estos mensajes, si slo podemos recibir mensajes desde un men, nicamente nos interesa la palabra de menor peso del parmetro wParam del mensaje. Modifiquemos el procedimiento de ventana para procesar los mensajes de nuestro men:

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam,

LPARAM lParam) { switch (msg) /* manipulador del mensaje */ { case WM_COMMAND: switch(LOWORD(wParam)) { case CM_PRUEBA: MessageBox(hwnd, "Comando: Prueba", "Mensaje de men", MB_OK); break; case CM_SALIR: MessageBox(hwnd, "Comando: Salir", "Mensaje de men", MB_OK); /* enva un mensaje WM_QUIT a la cola de mensajes */ PostQuitMessage(0); break; } break; case WM_DESTROY: /* enva un mensaje WM_QUIT a la cola de mensajes */ PostQuitMessage(0); break; default: /* para los mensajes de los que no nos ocupamos */ return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; }

Sencillo, no?. Observa que hemos usado la macro LOWORD para extraer el identificador del tem del parmetro wParam. Despus de eso, todo es ms fcil. Tambin se puede ver que hemos usado la misma funcin para salir de la aplicacin que para el mensaje WM_DESTROY: la funcin PostQuitMessage.

Ejemplo 2Este ejemplo contiene todo lo que hemos visto sobre los mens hasta ahora. Nombre Ejemplo 2 Fichero win002.zip Fecha 2004-01-18 Tamao 2328 bytes Descarga

Ficheros de recursosVeamos ahora una forma ms sencilla y ms frecuente de implementar mens.

Lo normal es implementar los mens desde un fichero de recursos, el sistema que hemos visto slo se usa en algunas ocasiones, para crear o modificar mens durante la ejecucin de la aplicacin. Es importante adquirir algunas buenas costumbres cuando se trabaja con ficheros de recursos. 1. Usaremos siempre etiquetas como identificadores para los tems de los mens, y nunca valores numricos literales. 2. Crearemos un fichero de cabecera con las definiciones de los identificadores, en nuestro ejemplo se llamar "ids.h". 3. Incluiremos este fichero de cabecera tanto en el fichero de recursos y como en el del cdigo fuente de nuestra aplicacin. Partimos de un proyecto nuevo: win003. Pero usaremos el cdigo modificado del ejemplo1. Para ello creamos un nuevo proyecto de tipo GUI, al que llamaremos Win003, y copiamos el contenido de "ejemplo1.c" en el fichero "main.cpp", al que renombraremos como "win003.c". A continuacin crearemos el fichero de identificadores. Aadimos el fichero de cabecera a nuestro proyecto. Si ests usando Dev-C++, sto se hace pulsando con el botn derecho del ratn sobre el nodo del proyecto y eligiendo el tem de "Buevo cdigo fuente" en el men que se despliega. Despus lo renombramos, el mecanismo es similar, pulsamos con el botn derecho sobre el tem "SiNombre1" y elegimos la opcin de "Renombrar archivo" del men que se despliegue. Como nuevo nombre elegimos: "ids.h". Introducimos en los identificadores:

#define CM_PRUEBA 100 #define CM_SALIR 101

En el fichero "win003.c" aadimos la lnea:

#include "ids.h"

Justo despus de la lnea "#include ". Ahora aadiremos el fichero de recursos. Para ello haremos lo mismo que hemos hecho con el fichero "ids.h", pero usaremos el nombre "win003.rc". En la primera lnea introducimos la siguiente lnea:

#include "ids.h"

Y a continuacin escribimos:

Menu MENU BEGIN POPUP "&Principal" BEGIN MENUITEM "&Prueba", CM_PRUEBA MENUITEM SEPARATOR MENUITEM "&Salir", CM_SALIR END END

En un fichero de recursos podemos crear toda la estructura de un men fcilmente. Este ejemplo crea una barra de men con una columna "Principal", con dos opciones: "Prueba" y "Salir", y con un separador entre ellas. La sintaxis es sencilla, definimos el men mediante una cadena identificadora, sin comillas, seguida de la palabra MENU. Entre las palabras BEGIN y END podemos incluir items, separadores u otras columnas. Para incluir columas usamos una sentencia del tipo POPUP seguida de la cadena que se mostrar como texto en el men. Cada POPUP se comporta del mismo modo que un MENU. Los tems se crean usado la palabra MENUITEM seguida de la cadena que se mostrar en el men, una coma, y el comando asignado a ese tem, que puede ser un nmero entero, o, como en este caso, una macro definida. Los separadores se crean usando MENUITEM seguido de la palabra SEPARATOR. Observars que las cadenas que se muestran en el men contienen un smbolo & en su interior, por ejemplo "&Prueba". Este smbolo indica que la siguiente letra puede usarse para activar la opcin del men desde el teclado, usando la tecla [ALT] ms la letra que sigue al smbolo &. Para indicar eso, en pantalla, esa letra se muestra subrayada, en este ejemplo "Prueba". Ya podemos cerrar el cuadro de edicin del fichero de recursos. Para ver ms detalles sobre el uso de este recurso puedes consultar las claves: MENU, POPUP y MENUITEM.

Cmo usar los recursos de men

Ahora tenemos varias opciones para usar el men que acabamos de crear. Primero veremos cmo cargarlo y asignarlo a nuestra ventana, sta es la forma que ms se parece a la del ejemplo del captulo anterior. Para ello basta con insertar este cdigo antes de llamar a la funcin ShowWindow:

HMENU hMenu; ... hMenu = LoadMenu(hInstance, "Menu"); SetMenu(hWnd, hMenu);

O simplemente:

SetMenu(hWnd, LoadMenu(hInstance, "Menu"));

La funcin LoadMenu se encarga de cargar el recurso de men, para ello hay que proporcionarle un manipulador de la instancia a la que pertenece el recurso y el nombre del men. Otro sistema, ms sencillo todava, es asignarlo como men por defecto de la clase. Para esto basta con la siguiente asignacin:

WNDCLASSEX wincl; ... wincl.lpszMenuName = "Menu";

Y por ltimo, tambin podemos asignar un men cuando creamos la ventana, especificndolo en la llamada a CreateWindowEx:

hwnd = CreateWindowEx( 0, "NUESTRA_CLASE", "Ejemplo 003", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, LoadMenu(hInstance, "Menu"), /* Carga y asignacin de men */ hInstance, NULL );

El tratamiento de los comandos procedentes del men es igual que en el apartado anterior.

Ejemplo 3Nombre Ejemplo 3 Fichero win003.zip Fecha 2004-01-18 Tamao 2478 bytes Descarga

Captulo 6 Dilogo bsicoLos cuadros de dilogo son la forma de ventana ms habitual de comunicacin entre una aplicacin Windows y el usuario. Para facilitar la tarea del usuario a la hora de introducir datos, existen varios tipos de controles, cada uno de ellos diseado para un tipo especfico de informacin. Los ms comunes son los "static", "edit", "button", "listbox", "scroll", "combobox", "group", "checkbutton" y "ratiobutton". A partir de Windows 95 se indrodujeron varios controles nuevos: "updown", "listview", "treeview", "gauge", "tab" y "trackbar". En realidad, un cuadro de dilogo es una ventana normal, aunque con algunas peculiaridades. Tambin tiene su procedimiento de ventana (procedimiento de dilogo), pero puede devolver un valor a la ventana que lo invoque. Igual que los mens, los cuadros de dilogo se pueden construir durante la ejecucin o a partir de un fichero de recursos.

Ficheros de recursosLa mayora de los compiladores de C/C++ que incluyen soporte para Windows poseen herramientas para la edicin de recursos: mens, dilogos, bitmaps, etc. Sin embargo considero que es interesante que aprendamos a construir nuestros recursos con un editor de textos, cada compilador tiene sus propios editores de recursos, y no tendra sentido explicar cada uno de ellos. El compilador que usamos "Dev C++", en su versin 4, tiene un editor muy limitado y no aconsejo su uso. De hecho, en la versin actual ya no se incluye, y los ficheros de recursos se editan en modo texto. De modo que aprenderemos a hacer cuadros de dilogo igual que hemos aprendido a hacer mens: usando el editor de texto. Para el primer programa de ejemplo de programa con dilogos, que ser el ejemplo 4, partiremos de nuevo del programa del ejemplo 1. Nuestro primer dilogo ser muy sencillo: un simple cuadro con un texto y un botn de "Aceptar". Este es el cdigo del fichero de recursos:

#include #include "IDS.H" Menu MENU BEGIN POPUP "&Principal" BEGIN MENUITEM "&Dilogo", CM_DIALOGO END END

DialogoPrueba DIALOG 0, 0, 118, 48 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Dilogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Mensaje de prueba", TEXTO, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 84, 8 CONTROL "Aceptar", IDOK, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14 END

Necesitamos incluir el fichero "windows.h" ya que en l se definen muchas constantes, como por ejemplo "IDOK" que es el identificador que se usa para el botn de "Aceptar". Tambin necesitaremos el fichero "ids.h", para definir los identificadores que usaremos en nuestro programa, por ejemplo el identificador del comando de men para abrir nuestro dilogo.

/* Identificadores */ /* Identificadores de comandos */ #define CM_DIALOGO 101 #define TEXTO 100

Lo primero que hemos definido es un men para poder comunicarle a nuestra aplicacin que queremos abrir un cuadro de dilogo. A continuacin est la definicin del dilogo, que se compone de varias lneas. Puedes ver ms detalles en el apartado de recursos dedicado al recurso dilogo. De momento bastar con un identificador, como el que usbamos para los mens, y adems las coordenadas y dimensiones del dilogo. En cuanto a los estilos, las constantes para definir los estilos de ventana, que comienzan con "WS_", puedes verlos con detalle en la seccin de constantes "estilos de ventana". Y los estilos de dilogos, que comienzan con "DS_", en "estilos de dilogo". Para empezar, hemos definido los siguientes estilos:q

q q q

DS_MODALFRAME: indica que se crear un cuadro de dilogo con un marco de dialogbox modal que puede combinarse con una barra de ttulo y un men de sistema. WS_POPUP: crea una ventana "pop-up". WS_VISIBLE: crea una ventana inicialmente visible. WS_CAPTION: crea una ventana con una barra de ttulo, (incluye el estilo WS_BORDER).

La siguiente lnea es la de CAPTION, en ella especificaremos el texto que aparecer en la barra de ttulo del dilogo. La lnea de FONT sirve para especificar el tamao y el tipo de fuente de caracteres que usar nuestro dilogo. Despus est la zona de controles, en nuestro ejemplo slo hemos incluido un texto esttico y un botn. Un control esttico (static) nos sirve para mostrar textos o rectngulos, que podemos usar para informar al usuario de algo, como etiquetas o como adorno. Para ms detalles ver control static.

CONTROL "Mensaje de prueba", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 84, 8

q q q

q q

q q q q

CONTROL es una palabra clave que indica que vamos a definir un control. A continuacin, en el parmetro text, introducimos el texto que se mostrar. id es el identificador del control. Como los controles static no se suelen manejar por las aplicaciones no necesitamos un identificador, as que ponemos -1. class es la clase de control, en nuestro caso "static". style es el estilo de control que queremos. En nuestro caso es una combinacin de un estilo esttico y varios de ventana: r SS_LEFT: indica un simple rectngulo y el texto suministrado se alinea en su interior a la izquierda. r WS_CHILD: crea el control como una ventana hija. r WS_VISIBLE: crea una ventana inicialmente visible. coordenada x del control. coordenada y del control. width: anchura del control. height: altura del control.

El control button nos sirve para comunicarnos con el dilogo, podemos darle comandos del mismo tipo que los que proporciona un men. Para ms detalles ver recurso button.

CONTROL "Aceptar", IDOK, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14

q q q

CONTROL es una palabra clave que indica que vamos a definir un control. A continuacin, en el parmetro text, introducimos el texto que se mostrar en su interior. id es el identificador del control. Nuestra aplicacin recibir este identificador junto con el

q q

q q q q

mensaje WM_COMMAND cuando el usuario active el botn. La etiqueta IDOK est definida en el fichero Windows.h. class es la clase de control, en nuestro caso "button". style es el estilo de control que queremos. En nuestro caso es una combinacin de varios estilos de button y varios de ventana: r BS_PUSHBUTTON: crea un botn corriente que enva un mensaje WM_COMMAND a su ventana padre cuando el usuario selecciona el botn. r BS_CENTER: centra el texto horizontalmente en el rea del botn. r WS_CHILD: crea el control como una ventana hija. r WS_VISIBLE: crea una ventana inicialmente visible. r WS_TABSTOP: define un control que puede recibir el foco del teclado cuando el usuario pulsa la tecla TAB. Presionando la tecla TAB, el usuario mueve el foco del teclado al siguiente control con el estilo WS_TABSTOP. coordenada x del control. coordenada y del control. width: anchura del control. height: altura del control.

Procedimiento de dilogoComo ya hemos dicho, un dilogo es bsicamente una ventana, y al igual que aquella, necesita un procedimiento asociado que procese los mensajes que le sean enviados, en este caso, un procedimiento de dilogo.

SintaxisBOOL CALLBACK DialogProc( HWND hwndDlg, // manipulador del cuadro de dilogo UINT uMsg, // mensaje WPARAM wParam, // primer parmetro del mensaje LPARAM lParam // segundo parmetro del mensaje );

q

q q q

hwndDlg identifica el cuadro de dilogo y es el manipulador de la ventana a la que est destinado el mensaje. msg es el cdigo del mensaje. wParam es el parmetro de tipo palabra asociado al mensaje. lParam es el parmetro de tipo doble palabra asociado al mensaje.

La diferencia con el procedimiento de ventana que ya hemos visto est en el tipo de valor de retorno, que es el caso del procedimiento de dilogo es de tipo booleano. Puedes consultar una sintaxis ms completa de esta funcin en DialogProc. Excepto en la respuesta al mensaje WM_INITDIALOG, el procedimiento de dilogo debe retornar con un valor no nulo si procesa el mensaje y cero si no lo hace. Cuando responde a un mensaje

WM_INITDIALOG, el procedimiento debe retornar cero si llama a la funcin SetFocus para poner el foco a uno de los controles del cuadro de dilogo. En otro caso, debe retornar un valor distinto de cero, y el sistema pondr el foco en el primer control del dilogo que pueda recibirlo.

Prototipo de procedimiento de dilogoEl prototipo es parecido al de los procedimientos de ventana:

BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

Implementacin de procedimiento de dilogo para nuestro ejemploNuestro ejemplo es muy sencillo, ya que nuestro dilogo slo puede proporcionar un comando, as que slo debemos responder a un tipo de mensaje WM_COMMAND y al mensaje WM_INITDIALOG. Segn hemos explicado un poco ms arriba, del mensaje WM_INITDIALOG debemos retornar con un valor distinto de cero si no llamamos a SetFocus, como es nuestro caso. Este mensaje lo usaremos para inicializar nuestro dilogo antes de que sea visible para el usuario, siempre que haya algo que inicializar, claro. Cuando procesemos el mensaje WM_COMMAND, que ser siempre el que procede del nico botn del dilogo, cerraremos el dilogo llamando a la funcin EndDialog y retornaremos con un valor distinto de cero. En cualquier otro caso retornamos con FALSE, ya que no estaremos procesando el mensaje. Nuestra funcin queda as:

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) /* manipulador del mensaje */ { case WM_INITDIALOG: return TRUE; case WM_COMMAND: EndDialog(hDlg, FALSE); return TRUE; } return FALSE; }

Bueno, slo nos falta saber cmo creamos un cuadro de dilogo. Para ello usaremos un comando de men, por lo tanto, el dilogo se activar desde el procedimiento de ventana.

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; switch (msg) /* manipulador del mensaje */ { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; return 0; break; case WM_COMMAND: switch(LOWORD(wParam)) { case CM_DIALOGO: DialogBox(hInstance, "DialogoPrueba", hwnd, DlgProc); break; } break; case WM_DESTROY: PostQuitMessage(0); /* enva un mensaje WM_QUIT a la cola de mensajes */ break; default: /* para los mensajes de los que no nos ocupamos */ return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; }

En este procedimiento hay varias novedades: Primero hemos declarado una variable esttica "hInstance" para tener siempre a mano un manipulador de la instancia actual. Para inicializar este valor hacemos uso del mensaje WM_CREATE, que se enva a una ventana cuando es creada, antes de que se visualice por primera vez. Aprovechamos el hecho de que nuestro procedimiento de ventana slo recibe una vez este mensaje y de que lo hace antes de poder recibir ningn otro mensaje o comando. En el futuro veremos que se usa para toda clase de inicializaciones. El mensaje WM_CREATE tiene como parmetro en lParam un puntero a una estructura CREATESTRUCT que contiene informacin sobre la ventana. En nuestro caso slo nos interesa el campo hInstance.

La otra novedad es la llamada a la funcin DialogBox, que es la que crea el cuadro de dilogo. Nota: Bueno, en realidad DialogBox no es una funcin, sino una macro, pero dado su formato y el modo en que se usa, la consideraremos como una funcin. Esta funcin necesita varios parmetros: 1. Un manipulador a la instancia de la aplicacin, que hemos obtenido al procesar el mensaje WM_CREATE. 2. Un identificador de recurso de dilogo, este es el nombre que utilizamos para el dilogo al crear el recurso, entre comillas. 3. Un manipulador a la ventana a la que pertenece el dilogo. 4. Y la direccin del procedimiento de ventana que har el tratamiento del dilogo. Y ya tenemos nuestro primer ejemplo del uso de dilogos, en captulos siguientes empezaremos a conocer ms detenidamente cmo usar cada uno de los controles bsicos: Edit, List Box, Scroll Bar, Static, Button, Combo Box, Group Box, Check Button y Radio Button. Le dedicaremos un captulo a cada uno de ellos.

Pasar parmetros a un cuadro de dilogoTenemos otra opcin a la hora de crear un dilogo. En lugar de usar la macro DialogBox, podemos usar la funcin DialogBoxParam, que nos permite enviar un parmetro extra al procedimiento de dilogo. Este parmetro se enva a travs del parmetro lParam del procedimiento de dilogo, y puede contener un valor entero, o lo que es mucho ms til, un puntero. Esta funcin tiene los mismos parmetros que DialogBox, ms uno aadido. Este quinto parmetro es el que podemos usar para pasar y recibir valores desde el procedimiento de dilogo. Por ejemplo, supongamos que queremos saber cuntas veces se ha invocado un dilogo. Para ello llevaremos la cuenta en el procedimiento de ventana, incrementando esa cuenta cada vez que recivamos un comando para mostrar el dilogo. Adems, pasaremos ese valor como parmetro lParam al procedimiento de dilogo.

static int veces; ... case WM_COMMAND: switch(LOWORD(wParam)) { case CM_DIALOGO: DialogBox(hInstance, "DialogoPrueba", hwnd, DlgProc); break; case CM_DIALOGO2: veces++; DialogBoxParam(hInstance, "DialogoPrueba2", hwnd, DlgProc2, veces); break;

} break;

Finalmente, nuestro procedimiento de dilogo tomar ese valor y lo usar para crear el texto de un control esttico. (Cmo funciona esto lo veremos en otro captulo, de momento sirva como ejemplo).

BOOL CALLBACK DlgProc2(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { char texto[25]; switch (msg) /* manipulador del mensaje */ { case WM_INITDIALOG: sprintf(texto, "Veces invocado: %d", lParam); SetWindowText(GetDlgItem(hDlg, TEXTO), texto); return TRUE; case WM_COMMAND: EndDialog(hDlg, FALSE); return TRUE; } return FALSE; }

Hemos usado la funcin estndar sprintf para conseguir un texto esttico a partir del parmetro lParam. Posteriormente, usamos ese texto para modificar el control esttico TEXTO. Usamos la misma plantilla de dilogo para ambos ejemplos, y aprovechamos el control esttico para mostrar nuestro mensaje. La funcin SetWindowText se usa para cambiar el ttulo de una ventana, pero tambin sirve para cambiar el texto de un control esttico. Cuando usemos cuadros de dilogo para pedir datos al usuario veremos que este modo de crearlos nos facilita en intercambio de datos entre la aplicacin y los procedimientos de dilogo. De otro modo tendramos que acudir a variables globales.

Ejemplo 4Nombre Ejemplo 4 Fichero win004.zip Fecha 2004-05-17 Tamao 2921 bytes Descarga

Captulo 7 Control bsico EditTal como hemos definido nuestro dilogo en el captulo 6, no tiene mucha utilidad. Los dilogos se usan para intercambiar informacin entre la aplicacin y el usuario, en ambas direcciones. El ejemplo 4 slo lo hace en una de ellas. En el captulo anterior hemos usado dos controles (un texto esttico y un botn), aunque sin saber exactamente cmo funcionan. En este captulo veremos el uso del control de edicin. Un control edit es una ventana de control rectangular que permite al usuario introducir y editar texto desde el teclado. Cuando est seleccionado muestra el texto que contiene y un cursor intermitente que indica el punto de insercin de texto. Para seleccionarlo el usuario puede hacer un click con el ratn en su interior o usar la tecla [TAB]. El usuario podr entonces introducir texto, cambiar el punto de insercin, o seleccionar texto para ser borrado o movido usando el teclado o el ratn. Un control de este tipo puede enviar mensajes a su ventana padre mediante WM_COMMAND, y la ventana padre puede enviar mensajes a un control edit en un cuadro de dilogo llamando a la funcin SendDlgItemMessage. Veremos algunos de estos mensajes en este captulo, y el resto el captulos ms avanzados.

Fichero de recursosEmpezaremos definiendo el control edit en el fichero de recursos, y lo aadiremos a nuestro dialogo de prueba.

#include #include "IDS.H" Menu MENU BEGIN POPUP "&Principal" BEGIN MENUITEM "&Dilogo", CM_DIALOGO END END DialogoPrueba DIALOG 0, 0, 118, 48 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Dilogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Texto:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 28, 8 CONTROL "", ID_TEXTO, "EDIT",

ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 36, 9, 76, 12 CONTROL "Aceptar", IDOK, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14 END

Hemos hecho algunas modificaciones ms. Para empezar, el control static se ha convertido en una etiqueta para el control edit, que indica al usuario qu tipo de informacin debe suministrar. Hemos aadido el control edit a continuacin del control static. Veremos que el orden en que aparecen los controles dentro del cuadro de dilogo es muy importante, al menos en aquellos controles que tengan el estilo WS_TABSTOP, ya que ese orden ser el mismo en que se activen los controles cuando usemos la tecla TAB. Para ms detalles acerca de los controles edit ver controles edit. Pero ahora veamos cmo hemos definido nuestro control edit:

CONTROL "", ID_TEXTO, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 36, 9, 76, 12

q q

q

q q

q q q q

CONTROL es una palabra clave que indica que vamos a definir un control. A continuacin, en el parmetro text, introducimos el texto que se mostrar en el interior del control, en este caso, ninguno. id es el identificador del control. Los controles edit necesitan un identificador para que la aplicacin pueda acceder a ellos. Usaremos un identificador definido en IDS.h. class es la clase de control, en nuestro caso "EDIT". style es el estilo de control que queremos. En nuestro caso es una combinacin de un estilo edit y varios de ventana: r ES_LEFT: indica que el texto en el interior del control se alinear a la izquierda. r WS_CHILD: crea el control como una ventana hija. r WS_VISIBLE: crea una ventana inicialmente visible. r WS_BORDER: se crea un control que tiene de borde una lnea fina. r WS_TABSTOP: define un control que puede recibir el foco del teclado cuando el usuario pulsa la tecla TAB. Presionando la tecla TAB, el usuario mueve el foco del teclado al siguiente control con el estilo WS_TABSTOP. coordenada x del control. coordenada y del control. width: anchura del control. height: altura del control.

El procedimiento de dilogo y los controles editPara manejar el control edit desde nuestro procedimiento de dilogo tendremos que hacer algunas

modificaciones. Para empezar, los controles edit tambin pueden generar mensajes WM_COMMAND, de modo que debemos diferenciar el control que origin dicho mensaje y tratarlo de diferente modo segn el caso.

case WM_COMMAND: if(LOWORD(wParam) == IDOK) EndDialog(hDlg, FALSE); return TRUE;

En nuestro caso sigue siendo sencillo: slo cerraremos el dilogo si el mensaje WM_COMMAND proviene del botn "Aceptar". La otra modificacin afecta al mensaje WM_INITDIALOG.

case WM_INITDIALOG: SetFocus(GetDlgItem(hDlg, ID_TEXTO)); return FALSE;

De nuevo es una modificacin sencilla, tan slo haremos que el foco del teclado se coloque en el control edit, de modo que el usuario pueda empezar a escribir directamente, tan pronto como el dilogo haya aparecido en pantalla. Para hacer eso usaremos la funcin SetFocus. Pero esta funcin requiere como parmetro el manipulador de ventana del control que debe recibir el foco, este manipulador lo conseguimos con la funcin GetDlgItem, que a su vez necesita como parmetros un manipulador del dilogo y el identificador del control.

Variables a editar en los cuadros de dilogoQuizs has notado que a nuestro programa le falta algo. Efectivamente, podemos introducir y modificar texto en el cuadro de dilogo, pero no podemos asignar valores iniciales al control de edicin ni tampoco podemos hacer que la aplicacin tenga acceso al texto introducido por el usuario. Lo primero que tenemos que tener es algn tipo de variable que puedan compartir los procedimientos de ventana de la aplicacin y el del dilogo. En nuestro caso se trata slo de una cadena, pero segn se aadan ms parmetros al cuadro de edicin, estos datos pueden ser ms complejos, as que usaremos un sistema que nos valdr en todos los casos.

Se trata de crear una estructura con todos los datos que queremos que el procedimiento de dilogo comparta con el procedimiento de ventana:

typedef struct stDatos { char Texto[80]; } DATOS;

Lo ms sencillo es que estos datos sean globales, pero no ser buena idea ya que no es buena prctica el uso de variables globales. Tampoco parece muy buena idea declarar los datos en el procedimiento de ventana, ya que este procedimiento se usa para todas las ventanas de la misma clase, y tendramos que definir los datos como estticos. Pero recordemos que tenemos un modo de pasar parmetros al cuadro de dilogo, usando la funcin DialogBoxParam, a travs del parmetro lParam. Aunque esta opcin parece que nos limita a valores enteros, y slo permite pasar valores al procedimiento de dilogo, en realidad se puede usar para pasar valores en ambos sentidos, bastar con enviar un puntero en lugar de un entero. Para ello haremos un casting del puntero al tipo LPARAM. Dentro del procedimiento de dilogo haremos otro casting de LPARAM al puntero. Esto nos permite declarar la variable que contiene los datos dentro del procedimiento de ventana, en este caso, de forma esttica.

static DATOS Datos; ... DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc, (LPARAM) &Datos);

En el caso del procedimiento de dilogo:

static DATOS *Datos; ... case WM_INITDIALOG: Datos = (DATOS *)lParam;

Daremos valores iniciales a las variables de la aplicacin, dentro del procedimiento de ventana, al procesar el mensaje WM_CREATE:

case WM_CREATE: /* Inicializacin de los datos de la aplicacin */ strcpy(Datos.Texto, "Inicial");

Iniciar controles editAhora tenemos que hacer que se actualice el contenido del control edit al abrir el cuadro de dilogo. El lugar adecuado para hacer esto es en el proceso del mensaje WM_INITDIALOG:

case WM_INITDIALOG: SendDlgItemMessage(hDlg, ID_TEXTO, EM_LIMITTEXT, 80, 0L); Datos = (DATOS *)lParam; SetDlgItemText(hDlg, ID_TEXTO, Datos->Texto); SetFocus(GetDlgItem(hDlg, ID_TEXTO)); return FALSE;

Hemos aadido dos llamadas a dos nuevas funciones del API. La primera es a SendDlgItemMessage, que enva un mensaje a un control. En este caso se trata de un mensaje EM_LIMITTEXT, que sirve para limitar la longitud del texto que se puede almacenar y editar en el control edit. Es necesario que hagamos esto, ya que el texto que puede almacenar nuestra estructura de datos est limitado a 80 caracteres. Tambin hemos aadido una llamada a la funcin SetDlgItemText, que hace exactamente lo que pretendemos: cambiar el contenido del texto en el interior de un control edit.

Devolver valores a la aplicacinTambin queremos que cuando el usuario est satisfecho con los datos que ha introducido, y pulse el botn de aceptar, el dato de nuestra aplicacin se actualice con el texto que hay en el control edit. Esto lo podemos hacer de varios modos. Como veremos en captulos ms avanzados, podemos responder a mensajes que provengan del control cada vez que cambia su contenido. Pero ahora nos limitaremos a leer ese contenido cuando procesemos el comando generado al pulsar el botn de "Aceptar".

case WM_COMMAND: if(LOWORD(wParam) == IDOK) {

GetDlgItemText(hDlg, ID_TEXTO, Datos->Texto, 80); EndDialog(hDlg, FALSE); } return TRUE;

Para eso hemos aadido la llamada a la funcin GetDlgItemText, que es simtrica a SetDlgItemText. Ahora puedes comprobar lo que pasa cuando abres varias veces seguidas el cuadro de dilogo modificando el texto cada vez. Con esto parece que ya controlamos lo bsico de los controles edit, pero an hay algo ms.

Aadir la opcin de cancelarEs costumbre dar al usuario la oportunidad de arrepentirse si ha modificado algo en un cuadro de dilogo y, por la razn que sea, cambia de idea. Para eso se suele aadir un segundo botn de "Cancelar". Empecemos por aadir dicho botn en el fichero de recursos:

DialogoPrueba DIALOG 0, 0, 118, 48 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Dilogo de prueba" FONT 8, "Helv" { CONTROL "Texto:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 28, 8 CONTROL "", ID_TEXTO, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 36, 9, 76, 12 CONTROL "Aceptar", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 8, 26, 45, 14 CONTROL "Cancelar", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 61, 26, 45, 14 }

Hemos cambiado las coordenadas de los botones, para que el de "Aceptar" aparezca a la izquierda. Adems, el botn de "Aceptar" lo hemos convertido en el botn por defecto, aadiendo el estilo BS_DEFPUSHBUTTON. Haciendo eso, podemos simular la pulsacin del botn de aceptar pulsando la tecla de "intro".

El identificador del botn de "Cancelar" es IDCANCEL, y est definido en Windows.h. Ahora tenemos que hacer que nuestro procedimiento de dilogo manipule el mensaje del botn de "Cancelar".

case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: GetDlgItemText(hDlg, ID_TEXTO, Datos->Texto, 80); EndDialog(hDlg, FALSE); break; case IDCANCEL: EndDialog(hDlg, FALSE); break; } return TRUE;

Como puedes ver, slo leemos el contenido del control edit si se ha pulsado el botn de "Aceptar".

Ejemplo 5Nombre Ejemplo 5 Fichero win005.zip Fecha 2004-05-17 Tamao 3077 bytes Descarga

Editar nmerosEn muchas ocasiones necesitaremos editar valores de nmeros enteros en nuestros dilogos. Para eso, el API tiene previstas algunas constantes y funciones, (aunque no es as para nmeros en coma flotante, para los que tendremos que crear nuestros propios controles). Bien, vamos a modificar nuestro ejemplo para editar valores numricos en lugar de cadenas de texto.

Fichero de recursos para editar enterosEmpezaremos aadiendo una constante al fichero de identificadores: "IDS.h":

#define ID_NUMERO 100

Y redefiniendo el control edit en el fichero de recursos, al que aadiremos el flag ES_NUMBER para que slo admita caracteres numricos:

DialogoPrueba DIALOG 0, 0, 118, 48 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Dilogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Nmero:", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 28, 8 CONTROL "", ID_NUMERO, "EDIT", ES_NUMBER | ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 36, 9, 76, 12 CONTROL "Aceptar", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 8, 26, 45, 14 CONTROL "Cancelar", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 61, 26, 45, 14 END

Variables a editar en los cuadros de dilogoAhora modificaremos la estructura de los datos para que el dato a editar sea de tipo numrico:

typedef struct stDatos { int Numero; } DATOS;

Al igual que antes, daremos valores iniciales a las variables del dilogo al procesar el mensaje WM_CREATE.

case WM_CREATE: /* Inicializacin de los datos de la aplicacin */ Datos.Numero = 123;

Por supuesto, pasaremos un puntero a esta estructura a la funcin DialogBoxParam, haciendo uso el parmetro lParam:

static DATOS Datos; ... DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc, (LPARAM)

&Datos);

Iniciar controles edit de enterosAhora tenemos que hacer que se actualice el contenido del control edit al abrir el cuadro de dilogo. El lugar adecuado para hacer esto es en el proceso del mensaje WM_INITDIALOG:

static DATOS *datos; ... case WM_INITDIALOG: datos = (DATOS *)lParam; SetDlgItemInt(hDlg, ID_NUMERO, (UINT)datos->Numero, FALSE); SetFocus(GetDlgItem(hDlg, ID_NUMERO)); return FALSE;

En este caso no es necesario limitar el texto que podemos editar en el control, ya que, como veremos, las propias funciones del API se encargan de capturar y convertir el contenido del control en un nmero, de modo que no tenemos que preocuparnos de que no quepa en nuestra variable. Tambin hemos modificado la funcin a la que llamamos para modificar el contenido del control, ahora usaremos SetDlgItemInt, que cambia el contenido de un control edit con un valor numrico.

Devolver valores a la aplicacinPor ltimo leeremos el contenido cuando procesemos el comando generado al pulsar el botn de "Aceptar".

BOOL NumeroOk; int numero; ... case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: numero = GetDlgItemInt(hDlg, ID_NUMERO, &NumeroOk, FALSE); if(NumeroOk) { datos->Numero = numero; EndDialog(hDlg, FALSE); } else MessageBox(hDlg, "Nmero no vlido", "Error", MB_ICONEXCLAMATION | MB_OK); break;

Para eso hemos aadido la llamada a la funcin GetDlgItemInt, que es simtrica a SetDlgItemInt. El proceso difiere del usado para capturar cadenas, ya que en este caso la funcin nos devuelve el valor numrico del contenido del control edit. Tambin devuelve un parmetro que indica si ha habido algn error durante la conversin. Si el valor de ese parmetro es TRUE, significa que la conversin se realiz sin problemas, si es FALSE, es que ha habido un error. Si nuestro programa detecta un error visualizar un mensaje de error y no permitir abandonar el cuadro de dilogo. Pero si ha habido un error, el valor de retorno de GetDlgItemInt ser cero. Esto nos causa un problema. Si leemos el valor directamente en datos->Numero y el usuario introduce un valor no vlido, y despus pulsa "Cancelar", el valor devuelto no ser el original, sino 0. Para evitar eso hemos usado una variable local, y el valor de datos->Numero slo se actualiza antes de salir con "Aceptar" y con un valor vlido. Por ltimo, hemos usado el flag BM_ICONEXCLAMATION en el MessageBox, que aade un icono al cuadro de mensaje y el sonido predeterminado para alertar al usuario.

Ejemplo 6Nombre Ejemplo 6 Fichero win006.zip Fecha 2004-05-17 Tamao 3141 bytes Descarga

Captulo 8 Control bsico ListBoxLos controles edit son muy tiles cuando la informacin a introducir por el usuario es imprevisible o existen muchas opciones. Pero cuando el nmero de opciones no es muy grande y son todas conocidas, es preferible usar un control ListBox. Ese es el siguiente control bsico que veremos. Un ListBox consiste en una ventana rectangular con una lista de cadenas entre las cuales el usuario puede escoger una o varias. El usuario puede seleccionar una cadena apuntndola y haciendo clic con el botn del ratn. Cuando una cadena se selecciona, se resalta y se enva un mensaje de notificacin a la ventana padre. Tambin se puede usar una barra de scroll con los listbox para desplazar listas muy largas o demasiado anchas para la ventana.

Ficheros de recursosEmpezaremos definiendo el control listbox en el fichero de recursos, y lo aadiremos a nuestro dilogo de prueba:

#include #include "IDS.H" Menu MENU BEGIN POPUP "&Principal" BEGIN MENUITEM "&Dilogo", CM_DIALOGO END END DialogoPrueba DIALOG 0, 0, 118, 135 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Dilogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Lista:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 28, 8 CONTROL "", ID_LISTA, "listbox", LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 9, 19, 104, 99 CONTROL "Aceptar", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 8, 116, 45, 14 CONTROL "Cancelar", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 61, 116, 45, 14 END

Hemos aadido el control listbox a continuacin del control static. Para ms detalles acerca de los controles listbox ver control listbox. Ahora veamos cmo hemos definido nuestro control listbox:

CONTROL "", ID_LISTA, "listbox", LBS_STANDARD | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 9, 19, 104, 99

q q

q

q q

q q q q

CONTROL es la palabra clave que indica que vamos a definir un control. A continuacin, en el parmetro text, en el caso de los listbox no tiene ninguna funcin. Lo dejaremos como cadena vaca. id es el identificador del control. Los controles listbox necesitan un identificador para que la aplicacin pueda acceder a ellos. Usaremos un identificador definido en IDS.h. class es la clase de control, en nuestro caso "LISTBOX". style es el estilo de control que queremos. En nuestro caso es una combinacin de un estilo listbox y varios de ventana: r LBS_STANDARD: ordena alfabticamente las cadenas en el listbox. La ventana padre recibe in mensaje de entrada cada vez que el usuario hacer click o doble click sobre una cadena. El list box tiene bordes en todos sus lados. r WS_CHILD: crea el control como una ventana hija. r WS_VISIBLE: crea una ventana inicialmente visible. r WS_TABSTOP: define un control que puede recibir el foco del teclado cuando el usuario pulsa la tecla TAB. Presionando la tecla TAB, el usuario mueve el foco del teclado al siguiente control con el estilo WS_TABSTOP. coordenada x del control. coordenada y del control. width: anchura del control. height: altura del control.

Iniciar controles listboxPara este ejemplo tambin usaremos variables estticas en el procedimiento de ventana para almacenar el valor de la cadena del listbox actualmente seleccionada.

// Datos de la aplicacin typedef struct stDatos { char Item[80]; } DATOS;

Daremos valores iniciales a las variables, al procesar el mensaje WM_CREATE del procedimiento de ventana:

static DATOS Datos; ... case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; /* Inicializacin de los datos de la aplicacin */ strcpy(Datos.Item, "Cadena n 3"); return 0;

Y pasaremos un puntero a la estructura con los datos como parmetro lParam de la funcin DialogBoxParam.

DialogBoxParam(hInstance, "DialogoPrueba", hwnd, DlgProc, (LPARAM)&Datos);

La caracterstica ms importante de los listbox es que contienen listas de cadenas. As que es imprescindible iniciar este tipo de controles, introduciendo las cadenas antes de que se muestre el dilogo. Eso se hace durante el proceso del mensaje WM_INITDIALOG dentro del procedimiento de dilogo. En este mismo mensaje obtenemos el puntero a la estructura de los datos que recibimos en el parmetro lParam.

static DATOS *Datos; ... case WM_INITDIALOG: Datos = (DATOS *)lParam; // Aadir cadenas. Mensaje: LB_ADDSTRING SendDlgItemMessage(hDlg, ID_LISTA, LB_ADDSTRING, 0, (LPARAM)"Cadena n 1"); SendDlgItemMessage(hDlg, ID_LISTA, LB_ADDSTRING, 0, (LPARAM)"Cadena n 4"); SendDlgItemMessage(hDlg, ID_LISTA, LB_ADDSTRING, 0, (LPARAM)"Cadena n 3"); SendDlgItemMessage(hDlg, ID_LISTA, LB_ADDSTRING, 0, (LPARAM)"Cadena n 2"); SendDlgItemMessage(hDlg, ID_LISTA, LB_SELECTSTRING, (UINT)-1, (LPARAM)Datos->Item); SetFocus(GetDlgItem(hDlg, ID_LISTA)); return FALSE;

Para aadir cadenas a un listbox se usa el mensaje LB_ADDSTRING mediante la funcin SendDlgItemMessage, que enva un mensaje a un control. Tambin podemos preseleccionar alguna de las cadenas del listbox, aunque esto no es muy frecuente ya que se suele dejar al usuario que seleccione una opcin sin sugerirle nada. Para seleccionar una de las cadenas tambin se usa un mensaje: LB_SELECTSTRING. Usaremos el

valor -1 en wParam para indicar que se busque en todo el listbox.

Devolver valores a la aplicacinTambin queremos que cuando el usuario est satisfecho con los datos que ha introducido, y pulse el botn de aceptar, el dato de nuestra aplicacin se actualice con el texto del tem seleccionado. De nuevo recurriremos a mensajes para pedirle al listbox el valor de la cadena actualmente seleccionada. En este caso se trata dos mensajes combinados, uno es LB_GETCURSEL, que se usa para averiguar el ndice de la cadena actualmente seleccionada. El otro es LB_GETTEXT, que devuelve la cadena del ndice que le indiquemos. Cuando trabajemos con memoria dinmica y con tems de longitud variable, ser interesante saber la longitud de la cadena antes de leerla desde el listbox. Para eso podemos usar el mensaje LB_GETTEXTLEN. Haremos esa lectura al procesar el comando IDOK, que se genera al pulsar el botn "Aceptar".

UINT indice; ... case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: indice = SendDlgItemMessage(hDlg, ID_LISTA, LB_GETCURSEL, 0, 0); SendDlgItemMessage(hDlg, ID_LISTA, LB_GETTEXT, indice, (LPARAM)Datos->Item); EndDialog(hDlg, FALSE); break; case IDCANCEL: EndDialog(hDlg, FALSE); break; } return TRUE;

Ejemplo 7Nombre Ejemplo 7 Fichero win007.zip Fecha 2004-05-17 Tamao 3153 bytes Descarga

Captulo 9 Control bsico ButtonLos controles button simulan el comportamiento de un pulsador o un interruptor. Pero slo cuando se comportan como un pulsador los llamaremos botones, cuando emulen interruptores nos referiremos a ellos como checkbox o radiobutton. Los botones se usan para que el usuario pueda ejecutar ciertas acciones o para dar rdenes a una aplicacin. En muchos aspectos, funcionan igual que los mens, y de hecho, ambos generan mensajes de tipo WM_COMMAND. Se componen normalmente de una pequea rea rectangular con un texto en su interior que identifica la accin que tienen asociada. En realidad ya hemos usado controles button en todos los ejemplos anteriores, pero los explicaremos ahora con algo ms de detalle.

Ficheros de recursosEmpezaremos definiendo el control button en el fichero de recursos, y lo aadiremos a nuestro dialogo de prueba:

#include #include "IDS.H" Menu MENU BEGIN POPUP "&Principal" BEGIN MENUITEM "&Dilogo", CM_DIALOGO END END DialogoPrueba DIALOG 0, 0, 130, 70 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Dilogo de prueba" FONT 8, "Helv" BEGIN CONTROL "Botones:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 9, 28, 8 CONTROL