Julio de 2004, Salvador Pozo Coronado
Con Clase: http:\winapi.conclase.net
Tabla de contenido
Tabla de contenido.
Introduccin Requisitos previos
Independencia de la mquina
Recursos
Ventanas
Eventos
Proyectos
Convenciones
Controles
1 Componentes de una ventana
El borde de la ventana
Barra de ttulo
Caja de minimizar
Caja de maximizar
Caja de cerrar
Caja de control de men
Men
Barra de men
Barra de desplazamiento horizontal
Barra de desplazamiento vertical
El rea de cliente
2 Notacin hngara Ejemplos
3 Estructura de un programa Windows GUI
Ficheros de cabecera
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (1 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Prototipos
Funcin de entrada, WinMain
Parmetros de entrada de WinMain
Funcin WinMain tpica
Declaracin
Inicializacin
Bucle de mensajes
Definicin de funciones
4 El procedimiento de ventana Sintaxis
Prototipo de procedimiento de ventana
Implementacin de procedimiento de ventana simple
Primer ejemplo de programa Windows GUI
5 Mens 1 Usando las funciones para insercin tem a tem
Uso bsico de MessageBox
Respondiendo a los mensajes del men
Ejemplo 2
Ficheros de recursos
Cmo usar los recursos de men
Ejemplo 3
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (2 de 16) [25/07/2004 19:46:31]
Tabla de contenido
6 Dilogo bsico Ficheros de recursos
Procedimiento de dilogo
Sintaxis
Prototipo de procedimiento de dilogo
Implementacin de procedimiento de dilogo para nuestro ejemplo
Pasar parmetros a un cuadro de dilogo
Ejemplo 4
7 Control bsico Edit Fichero de recursos
El procedimiento de dilogo y los controles edit
Variables a editar en los cuadros de dilogo
Iniciar controles edit
Devolver valores a la aplicacin
Aadir la opcin de cancelar
Ejemplo 5
Editar nmeros
Fichero de recursos para editar enteros
Variables a editar en los cuadros de dilogo
Iniciar controles edit de enteros
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (3 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Devolver valores a la aplicacin
Ejemplo 6
8 Control bsico ListBox Ficheros de recursos
Iniciar controles listbox
Devolver valores a la aplicacin
Ejemplo 7
9 Control bsico Button
Ficheros de recursos
Iniciar controles button
Tratamiento de acciones de los controles button
Ejemplo 8
10 Control bsico Static Ficheros de recursos
Iniciar controles static
Tratamiento de acciones de los controles static
Ejemplo 9
11 Control bsico ComboBox Ficheros de recursos
Iniciar controles ComboBox
Devolver valores a la aplicacin
Ejemplo 10
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (4 de 16) [25/07/2004 19:46:31]
Tabla de contenido
12 Control bsico Scrollbar Ficheros de recursos
Iniciar controles Scrollbar
Iniciar controles scrollbar: estructura SCROLLINFO
Procesar los mensajes procedentes de controles Scrollbar
Procesar mensajes de scrollbar usando SCROLLINFO
Devolver valores a la aplicacin
Ejemplo 11
Ejemplo 12
13 Control bsico Groupbox Ficheros de recursos
Iniciar controles GroupBox
Devolver valores a la aplicacin
Ejemplo 13
14 Control bsico Checkbox Ficheros de recursos
Iniciar controles CheckBox
Procesar mensajes de los CheckBox
Devolver valores a la aplicacin
Ejemplo 14
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (5 de 16) [25/07/2004 19:46:31]
Tabla de contenido
15 Control bsico RadioButton Ficheros de recursos
Iniciar controles RadioButton
Procesar mensajes de los RadioButtons
Devolver valores a la aplicacin
Ejemplo 15
16 El GDI Objetos del GDI
17 Objetos bsicos del GDI:El Contexto de dispositivo, DC
Actualizar el rea de cliente de una ventana, el mensaje WM_PAINT
Colores
18 Objetos bsicos del GDI:La pluma (Pen)
Plumas de Stock
Plumas cosmticas y geomtricas
Crear una pluma
Seleccionar una pluma
Destruir una pluma
Ejemplo 16
19 Funciones para el trazado de lneas
Trazado de arcos, funcin Arc
Curvas Bzier
Funciones Poly
Funcin LineDDA y funciones callback LineDDAProc
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (6 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Ejemplo 17
20 Objetos bsicos del GDI:El pincel (Brush)
Pinceles lgicos Pinceles slidos
Pinceles de Stock
Pinceles de tramas (Hatch)
Pinceles de patrones
Crear un pincel
Seleccionar un pincel
Destruir un pincel
Ejemplo 18
21 Funciones para el trazado de figuras rellenas
Pintando trozos de elipses, funciones Chord y Pie
Modos de relleno de polgonos
Ejemplo 19
22 Objetos bsicos del GDI:La paleta (Palette)
Capacidades de Color de los dispositivos
Definiciones de valores de color
Aproximaciones de colores y mezclas de pixels (dithering)
Mezclas de colores (ROP)
Paletas de colores
La paleta por defecto
Paleta lgica
Paleta de sistema
Ejemplo 20
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (7 de 16) [25/07/2004 19:46:31]
Tabla de contenido
23 Objetos bsicos del GDI:El Mapa de Bits (Bitmap)
Tipos de mapas de bits
Crear un mapa de bits
Fichero de recursos
Fichero BMP
Mostrar un mapa de bits
Funciones de visualizacin de mapas de bits
BitBlt
StretchBlt
PlgBlt (Slo en Windows NT)
(Slo en Windows NT)
Cdigos ROP ternarios
Cdigos ROP cudruples
Pinceles creados a partir de mapas de bits PatBlt
ExtFloodFill
Estructuras de datos BITMAP
Modos de estiramiento (stretch modes)
Mapas de bits de stock
Ejemplo 21
24 Objetos bsicos del GDI:La Fuente (Font)
Mostrar un texto simple
Cambiar el color del texto
Ejemplo 22
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (8 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Crear fuentes personalizadas
Altura y anchura media de carcter
El ngulo de escape
El ngulo de orientacin
Peso
Cursiva
Subrayado
Tachado
Conjunto de caracteres
Precisin de salida
Precisin de recorte
Calidad
Paso y familia
Nombre
Fuentes de stock
Alineamientos de texto
Separacin de caracteres
Medidas de cadenas
Justificar texto
Ejemplo 23
25 Objetos bsicos del GDI:Rectngulos y Regiones
Rectngulos
Funciones para trabajar con rectngulos Asignar rectngulos
Comparaciones de rectngulos
Modificar rectngulos
Operaciones con rectngulos
Ejemplo 24
Regiones
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (9 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Funciones para regiones Crear regiones
Combinar regiones
Comparar regiones
Rellenar regiones
Mover una regin
Comprobar posiciones
Destruir regiones
Ejemplo 25
26 Objetos bsicos del GDI:El camino (Path)
Crear un camino
Operaciones con caminos
Ejemplo 26
27 Objetos bsicos del GDI:El recorte (Clipping)
Regiones de recorte y el mensaje WM_PAINT
Funciones relacionadas con el recorte
Seleccionar regiones de recorte
Caminos de recorte
Ejemplo 27
28 Objetos bsicos del GDI:Espacios de coordenadas y transformaciones
Definiciones
Transformaciones Traslaciones
Cambio de escala
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (10 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Rotaciones
Cambio de ejes
Reflexiones
Aplicar transformaciones
Combinar transformaciones
Cambios de escala y plumas
Ejemplo 28
Ventanas y viewports Extensiones
Orgenes
Mapeos
Modos de mapeo predefinidos
Modo por defecto
Transformaciones definidas por el usuario
Modos grficos y sentido de los arcos
Otras funciones
Ejemplo 29
29 Objetos bsicos del GDI:Plumas geomtricas
Atributos de las plumas geomtricas Anchura
Estilo de lnea
Color
Patrn
Rayado
Estilo de final (tapn)
Estilo de unin
Crear una pluma geomtrica
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (11 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Seleccionar una pluma geomtrica
Destruir una pluma geomtrica
30 Objetos bsicos de usuario:El Caret
Recibir y perder el foco
Crear y destruir carets
Mostrar y ocultar carets
Procesar mensajes WM_PAINT
Cambiar posicin de un caret
Cambiar velocidad de parpadeo de un caret
Ejemplo 31
31 Objetos bsicos del usuario:El icono
Punto activo
Tamaos
Asociar iconos a una aplicacin
Tipos
Iconos en ficheros de recursos
Iconos en controles estticos
Mostrar iconos
Destruccin de iconos
Ejemplo 32
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (12 de 16) [25/07/2004 19:46:31]
Tabla de contenido
32 Objetos bsicos del usuario:El cursor
Cursor de clase
Cursores de recursos
Cursores estndar
Similitud entre iconos y cursores
El punto activo (Hot Spot)
Crear cursores
Posicin del cursor
Apariencia
Modificar el cursor de clase
El mensaje WM_SETCURSOR
Ocultar y mostrar
Confinar el cursor
Destruccin de cursores
Ejemplo 33
33 El ratn Capturar el ratn
Configuracin
Mensajes Mensajes del rea de cliente
Mensajes del rea de no cliente
Mensaje WM_NCHITTEST
Mensaje WM_MOUSEACTIVATE
Otros mensajes de ratn
Mensaje WM_MOUSEWHEEL (Windows NT)
Trazar eventos del ratn (Windows NT)
Mensaje WM_MOUSELEAVE (Windows NT)
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (13 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Mensaje WM_MOUSEHOVER (Windows NT)
Ejemplo 34
Arrastrar objetos
Ejemplo 35
34 El teclado El Foco del teclado
Ventanas inhibidas
Ejemplo 36
Mensajes de pulsacin de teclas
Nombres de teclas
El bucle de mensajes
Ejemplo 37
Mensajes de carcter Teclas muertas
Estado de teclas
Ejemplo 38
Hot keys
Ejemplo 39
Cdigos de teclas virtuales
35 Cadenas Recursos de cadenas Fichero de recursos
Cargar cadenas desde recursos
Funciones para cadenas
Ejemplo 40
36 Aceleradores Recursos de aceleradores Fichero de recursos
Cargar aceleradores desde recursos
Bucle de mensajes para usar aceleradores
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (14 de 16) [25/07/2004 19:46:31]
Tabla de contenido
Crear tablas de aceleradores sin usar recursos
Combinar aceleradores y mens
Aceleradores globales
Diferencia entre acelerador y men
Ejemplo 41
37 Mens 2 Marcas en mens Mens como checkboxes
Mens como radiobuttons
Ejemplo 42
Inhibir y oscurecer tems
Ejemplo 43
Ms sobre ficheros de recursos
Sentencia MENUITEM y POPUP
Detalles sobre cadenas de tems
Sentencia MENUEX
Items marcados y no marcados
Items activos, inactivos u oscurecidos
Separadores y lneas de ruptura
Cargar recursos
tems por defecto
Ejemplo 44
Mens flotantes o contextuales
Ejemplo 45
Acceso por teclado Mnemnicos
Aceceso de teclado estndar
Aceleradores
Modificar mens
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (15 de 16) [25/07/2004 19:46:31]
Tabla de contenido
El men de sistema Modificar el men de sistema
Ejemplo 46
Destruccin de mens
Mensajes de men
Mapas de bits en tems de men
Modificar mapas de bits de check
Items de mapas de bits
Ejemplo 47
Glosario
Tabla de contenido
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=999 (16 de 16) [25/07/2004 19:46:31]
Introduccin
Introduccin
Requisitos previos
Para 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 mquina
Los 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.
Recursos
Un 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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=000 (1 de 5) [25/07/2004 19:46:32]
Introduccin
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.
Ventanas
La 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.
Eventos
Los 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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=000 (2 de 5) [25/07/2004 19:46:32]
Introduccin
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:
Proyectos
Debido 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=000 (3 de 5) [25/07/2004 19:46:32]
Introduccin
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.
Convenciones
En 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".
Controles
Los 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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=000 (4 de 5) [25/07/2004 19:46:32]
Introduccin
aprendemos a manejarlos.
Los ms importantes y conocidos son:
l control estatic: son etiquetas, marcos, iconos o dibujos.l control edit: permiten que el usuario introduzca datos alfanumricos en
la aplicacin.l control list box: el usuario puede escoger entre varias opciones de una
lista.l control combo box: es una combinacin entre un edit y un list box.l control scroll bar: barras de desplazamiento, para la introduccin de
valores entre mrgenes definidos.l control button: realizan acciones o comandos, de button de derivan
otros dos controles muy comunes: m control check box: permite leer variables de dos estados
"checked" o "unchecked"m control radio button: se usa en grupos, dentro de cada grupo
slo uno puede ser activado.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=000 (5 de 5) [25/07/2004 19:46:32]
1 Componentes ventana
Captulo 1 Componentes de una ventana
Veamos 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 ventana
Hay 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 ttulo
Zona 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 minimizar
Pequea 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 maximizar
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=001 (1 de 3) [25/07/2004 19:46:32]
1 Componentes ventana
Pequea 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 cerrar
Pequea rea cuadrada situada en la parte derecha de la barra de ttulo que sirve para cerrar la ventana. (5)
Caja de control de men
Pequea 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).
Men
O 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 men
Zona situada debajo de la barra de ttulo, contiene los mens de la aplicacin (7).
Barra de scroll horizontal
Barra situada en la parte inferior de la ventana, permite desplazar horizontalmente la vista del rea de cliente (8).
Barra de scroll vertical
Barra situada en la parte derecha de la ventana, permite desplazar verticalmente la vista del rea de cliente (9).
El rea de cliente
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=001 (2 de 3) [25/07/2004 19:46:32]
1 Componentes ventana
Es 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).
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=001 (3 de 3) [25/07/2004 19:46:32]
2 Notacin Hngara
Captulo 2 Notacin Hngara
La notacin hngara es un sistema usado normalmente para crear los nombres de variables 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.
Consiste en prefijos en minsculas que se aaden a los nombres de las variables, y que indican su tipo. El resto del nombre indica, lo ms claramente posible, la funcin que realiza la variable.
Prefijo Significadob Booleanoc Carcter (un byte)dw Entero largo de 32 bits sin signo (DOBLE WORD)f Flags empaquetados en un entero de 16 bitsh Manipulador de 16 bits (HANDLE)l Entero largo de 32 bitslp Puntero a entero largo de 32 bitslpfn Puntero largo a una funcin que devuelve un enterolpsz Puntero largo a una cadena terminada con ceron Entero de 16 bitsp Puntero a entero de 16 bitspt Coordenadas (x, y) empaquetadas en un entero de 32 bitsrgb Valor de color RGB empaquetado en un entero de 32 bitssz Cadena terminada en cerow Entero corto de 16 bits sin signo (WORD)Ejemplos
nContador: 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=002 [25/07/2004 19:46:33]
3 Estructura de programa
Captulo 3 Estructura de un programa Windows GUI
Hay 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:
Cabeceras
Lo 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.
Prototipos
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=003 (1 de 5) [25/07/2004 19:46:34]
3 Estructura de programa
Cada 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, WinMain
La 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:
l 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.
l 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.
l lpszCmdParam, esta cadena contiene los argumentos de entrada del comando de lnea.
l 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 tpica
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=003 (2 de 5) [25/07/2004 19:46:34]
3 Estructura de programa
int 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;}
Declaracin
En la primera zona declararemos las variables que necesitamos para nuestra
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=003 (3 de 5) [25/07/2004 19:46:34]
3 Estructura de programa
funcin WinMain, que como mnimo sern tres:
l HWND hWnd, un manipulador para la ventana principal de la aplicacin. Ya sabemos que nuestra aplicacin necesitar al menos una ventana.
l MSG Message, una variable para manipular los mensajes que lleguen a nuestra aplicacin.
l 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.
Inicializacin
Esta 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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=003 (4 de 5) [25/07/2004 19:46:34]
3 Estructura de programa
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 funciones
En esta parte definiremos, entre otras cosas, los procedimientos de ventana, que se encargan de procesar los mensajes que lleguen a cada ventana.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=003 (5 de 5) [25/07/2004 19:46:34]
4 Proc. de ventana
Captulo 4 El procedimiento de ventana
Cada 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.
Sintaxis
LRESULT CALLBACK WindowProcedure( HWND hwnd, // Manipulador de ventana UINT msg, // Mensaje WPARAM wParam, // Parmetro palabra, vara LPARAM lParam // Parmetro doble palabra, vara );
l hwnd es el manipulador de la ventana a la que est destinado el mensaje.l msg es el cdigo del mensaje.l wParam es el parmetro de tipo palabra asociado al mensaje.l 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 ventana
LRESULT 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 */
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=004 (1 de 2) [25/07/2004 19:46:34]
4 Proc. de ventana
{ 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 Windows
Ya 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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=004 (2 de 2) [25/07/2004 19:46:34]
5 Mens 1
Captulo 5 Mens 1
Ahora 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 tem
Este 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 */
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (1 de 7) [25/07/2004 19:46:35]
5 Mens 1
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:
l Puede ser un identificador de comando, este identificador se usar para comunicar a la aplicacin si el usuario selecion un determinado tem.
l Un manipulador de men, si el tem tiene el flag MF_POPUP, en este caso hay que hacer un casting a (UINT).
l 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (2 de 7) [25/07/2004 19:46:35]
5 Mens 1
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 MessageBox
Antes 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 men
Las 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;
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (3 de 7) [25/07/2004 19:46:35]
5 Mens 1
} 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 2
Este ejemplo contiene todo lo que hemos visto sobre los mens hasta ahora.
Nombre Fichero Fecha Tamao Descarga
Ejemplo 2 win002.zip 2004-01-18 2328 bytes
Ficheros de recursos
Veamos 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (4 de 7) [25/07/2004 19:46:35]
5 Mens 1
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 MENUBEGIN POPUP "&Principal" BEGIN MENUITEM "&Prueba", CM_PRUEBA MENUITEM SEPARATOR MENUITEM "&Salir", CM_SALIR ENDEND
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:
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (5 de 7) [25/07/2004 19:46:35]
5 Mens 1
"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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (6 de 7) [25/07/2004 19:46:35]
5 Mens 1
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 3
Nombre Fichero Fecha Tamao Descarga
Ejemplo 3 win003.zip 2004-01-18 2478 bytes
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=005 (7 de 7) [25/07/2004 19:46:35]
6 Dilogo bsico
Captulo 6 Dilogo bsico
Los 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 recursos
La 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 ENDEND
DialogoPrueba DIALOG 0, 0, 118, 48STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTIONCAPTION "Dilogo de prueba"FONT 8, "Helv"BEGIN CONTROL "Mensaje de prueba", TEXTO, "static", SS_LEFT | WS_CHILD | WS_VISIBLE,
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (1 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
8, 9, 84, 8 CONTROL "Aceptar", IDOK, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14END
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:
l DS_MODALFRAME: indica que se crear un cuadro de dilogo con un marco de dialog-box modal que puede combinarse con una barra de ttulo y un men de sistema.
l WS_POPUP: crea una ventana "pop-up".l WS_VISIBLE: crea una ventana inicialmente visible.l 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (2 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
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
l CONTROL es una palabra clave que indica que vamos a definir un control.l A continuacin, en el parmetro text, introducimos el texto que se mostrar.l 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.l class es la clase de control, en nuestro caso "static".l style es el estilo de control que queremos. En nuestro caso es una combinacin de un
estilo esttico y varios de ventana: m SS_LEFT: indica un simple rectngulo y el texto suministrado se alinea en su
interior a la izquierda. m WS_CHILD: crea el control como una ventana hija. m WS_VISIBLE: crea una ventana inicialmente visible.
l coordenada x del control.l coordenada y del control.l width: anchura del control.l 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
l CONTROL es una palabra clave que indica que vamos a definir un control.l A continuacin, en el parmetro text, introducimos el texto que se mostrar en su
interior.l id es el identificador del control. Nuestra aplicacin recibir este identificador junto
con el mensaje WM_COMMAND cuando el usuario active el botn. La etiqueta IDOK est definida en el fichero Windows.h.
l class es la clase de control, en nuestro caso "button".l style es el estilo de control que queremos. En nuestro caso es una combinacin de
varios estilos de button y varios de ventana: m BS_PUSHBUTTON: crea un botn corriente que enva un mensaje
WM_COMMAND a su ventana padre cuando el usuario selecciona el botn.m BS_CENTER: centra el texto horizontalmente en el rea del botn.m WS_CHILD: crea el control como una ventana hija.m WS_VISIBLE: crea una ventana inicialmente visible.m 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (3 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
l coordenada x del control.l coordenada y del control.l width: anchura del control. l height: altura del control.
Procedimiento de dilogo
Como 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.
Sintaxis
BOOL CALLBACK DialogProc( HWND hwndDlg, // manipulador del cuadro de dilogo UINT uMsg, // mensaje WPARAM wParam, // primer parmetro del mensaje LPARAM lParam // segundo parmetro del mensaje );
l hwndDlg identifica el cuadro de dilogo y es el manipulador de la ventana a la que est destinado el mensaje.
l msg es el cdigo del mensaje.l wParam es el parmetro de tipo palabra asociado al mensaje.l 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 dilogo
El prototipo es parecido al de los procedimientos de ventana:
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
Implementacin de procedimiento de dilogo para nuestro ejemplo
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (4 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
Nuestro 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;
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (5 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
}
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 dilogo
Tenemos 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (6 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
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 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 4
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (7 de 8) [25/07/2004 19:46:36]
6 Dilogo bsico
Nombre Fichero Fecha Tamao Descarga
Ejemplo 4 win004.zip 2004-05-17 2921 bytes
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=006 (8 de 8) [25/07/2004 19:46:36]
7 Control Edit
Captulo 7 Control bsico Edit
Tal 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 recursos
Empezaremos 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 ENDEND
DialogoPrueba DIALOG 0, 0, 118, 48STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTIONCAPTION "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,
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (1 de 10) [25/07/2004 19:46:37]
7 Control Edit
36, 9, 76, 12 CONTROL "Aceptar", IDOK, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 56, 26, 50, 14END
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
l CONTROL es una palabra clave que indica que vamos a definir un control.l A continuacin, en el parmetro text, introducimos el texto que se mostrar
en el interior del control, en este caso, ninguno.l 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.
l class es la clase de control, en nuestro caso "EDIT".l style es el estilo de control que queremos. En nuestro caso es una
combinacin de un estilo edit y varios de ventana:m ES_LEFT: indica que el texto en el interior del control se alinear a
la izquierda. m WS_CHILD: crea el control como una ventana hija.m WS_VISIBLE: crea una ventana inicialmente visible.m WS_BORDER: se crea un control que tiene de borde una lnea fina.m 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.
l coordenada x del control.l coordenada y del control.l width: anchura del control. l height: altura del control.
El procedimiento de dilogo y los controles
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (2 de 10) [25/07/2004 19:46:37]
7 Control Edit
edit
Para 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 dilogo
Quizs 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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (3 de 10) [25/07/2004 19:46:37]
7 Control Edit
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:
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (4 de 10) [25/07/2004 19:46:37]
7 Control Edit
case WM_CREATE: /* Inicializacin de los datos de la aplicacin */ strcpy(Datos.Texto, "Inicial");
Iniciar controles edit
Ahora 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 aplicacin
Tambin 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:
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (5 de 10) [25/07/2004 19:46:37]
7 Control Edit
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 cancelar
Es 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, 48STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTIONCAPTION "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
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (6 de 10) [25/07/2004 19:46:37]
7 Control Edit
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 5
Nombre Fichero Fecha Tamao Descarga
Ejemplo 5 win005.zip 2004-05-17 3077 bytes
Editar nmeros
En 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 enteros
Empezaremos aadiendo una constante al fichero de identificadores: "IDS.h":
#define ID_NUMERO 100
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (7 de 10) [25/07/2004 19:46:37]
7 Control Edit
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, 48STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTIONCAPTION "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, 14END
Variables a editar en los cuadros de dilogo
Ahora 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 enteros
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (8 de 10) [25/07/2004 19:46:37]
7 Control Edit
Ahora 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 aplicacin
Por 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.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (9 de 10) [25/07/2004 19:46:37]
7 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 6
Nombre Fichero Fecha Tamao Descarga
Ejemplo 6 win006.zip 2004-05-17 3141 bytes
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=007 (10 de 10) [25/07/2004 19:46:37]
8 Control ListBox
Captulo 8 Control bsico ListBox
Los 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 recursos
Empezaremos 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 ENDEND
DialogoPrueba DIALOG 0, 0, 118, 135STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTIONCAPTION "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, 14END
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
l CONTROL es la palabra clave que indica que vamos a definir un control.
http://localhost/conclase/winapi/curso/para-pdf/index.php?cap=008 (1 de 4) [25/07/2004 19:46:38]
8 Control ListBox
l A continuacin, en el parmetro text, en el caso de los listbox no tiene ninguna funcin. Lo dejaremos como cadena vaca.
l 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.
l class es la clase de control, en nuestro caso "LISTBOX".l style es el estilo de control