Versión: 1.1
Autor: Ximorro
Objetivo: mostrar cómo insertar un botón en un GUI y hacerlo interactivo con el usuario.
Dificultad: MUY básico.
Conceptos clave: GUI, botón, evento.
Veo que algunos foreros tienen dificultades para manejar controles en los formularios o ventanas, también llamados ampliamente GUI, aunque esa palabra esté formada por siglas que vienen del inglés.
Para las cuestiones básicas se recomienda encarecidamente consultar en la ayuda oficial que viene con el programa, pues para estos casos es más que suficiente. Si no entendéis la ayuda en inglés en este foro encontraréis un enlace a la traducción española, el último a fecha de escritura de este tutorial es este:
http://www.emesn.com/autoitforum/viewto ... f=2&t=1903
En cualquier caso voy a exponer un ejemplo muy simple que explicaré con mayor detalle de lo que se puede encontrar en la ayuda, a ver si así afianzamos algunos conceptos y con estas ideas claras podemos avanzar más rápidamente y con paso firme cuando creemos GUIs más complejos. Y es que sin saber lo que se está haciendo es un poco complicado crear GUIs en particular o programar en general...
Analicemos pues este sencillo ejemplo que simplemente crea un botón que minimiza el formulario al ser pulsado.
Código: Seleccionar todo
#include <GUIConstantsEx.au3>
GUICreate("Gui de un botón", 200, 100)
$btnMini = GUICtrlCreateButton("&Minimizar", 60,30, 80,30)
GUISetState(@SW_SHOW)
While 1
Switch GUIGetMsg()
Case $btnMini
GUISetState(@SW_MINIMIZE)
Case $GUI_EVENT_CLOSE
ExitLoop
EndSwitch
WEnd
Antes de entrar en detalle en el programa hablemos de qué es un evento, pues este es un concepto relacionado con GUIs y que manejaremos y veremos mucho por el foro (y otros muchos sitios):
.- Un evento (en nuestro caso) es una indicación de que algo ha ocurrido en nuestro GUI, casi siempre referido a una interacción del usuario, aunque algunos pueden ser lanzados por el sistema. Por ejemplo se disparará un evento cuando se cliquee un botón, cuando se pulse el aspa de cerrar que hay en la barra de título del formulario, etc... Hay que hacer notar que AutoIt tiene un sistema más bien sencillo de eventos, no notifica absolutamente todo y para hacer cosas más complejas habrá que usar mecanismos diferentes a los aquí descritos. Pero no os asustéis, con el sistema básico de eventos se pueden hacer GUIs muy complejos.
.- AutoIt tiene dos modos para manejar eventos, modo MessageLoop y modo OnEvent.
.- Modo MessageLoop, es decir, modo de bucle de mensajes, es probablemente el más usado. En este modo AutoIt nos manda mensajes indicando que se han disparado eventos, nosotros tenemos que preguntar expresamente si ha llegado algún mensaje de evento, si ha llegado se procesa, si no pues seguimos comprobando hasta que llegue uno. Este es el modo usado en este ejemplo.
.- modo OnEvent, o modo EnEvento..., en este modo cuando se activa un evento el programa es interrumpido esté donde esté e inmediatamente se ejecuta la función que hayamos creado para manejar el evento, cuando dicha función finaliza el programa es reanudado allá donde estuviera trabajando. Este modo está fuera del alcance de este tutorial.
Veamos cómo se usa el modo de bucle de mensajes para manejar nuestro pequeño GUI:
La primera línea del programa es una directiva #include, esto añade una librería a nuestro programa que incluye funciones y/o constantes o variables predefinidas, en nuestro caso incluimos GUIConstantsEx.au3 porque es donde está definido, entre otros, el mensaje $GUI_EVENT_CLOSE, que nos notificará cuando se produzca un evento de clausura del formulario.
A continuación se crea la ventana del formulario con GUICreate, donde indicamos el título y el tamaño (se pueden añadir otras cosas, como posición o estilo).
Después de crear la ventana (el GUI), creamos los controles que van en ella (botones, etiquetas, cajas de texto, etc.). En este caso creamos sólo un botón con GUICtrlCreateButton. Fijáos en la asignación a la variable $btnMini, esto lo hacemos para referenciar el botón posteriormente. Asignar los controles a variables es opcional, depende de lo que vayamos a hacer después con ellos, por ejemplo una etiqueta que vaya a quedar estática la crearemos y la dejaremos fija para siempre, con lo que no será necesario referenciarla. Por cierto, el GUI también podríamos asignarlo a una variable, si nos hiciera falta.
He puesto una cosita de regalo, ese "&" antes de la M en "&Minimizar" indica que esa letra estará subrayada en el botón del GUI, con lo que al presionar ALT-M cuando la ventana esté activa será como pinchar el botón con el ratón (dicho de otra manera, es otra forma de lanzar el evento de cliqueo del botón)
Una vez creados todos los controles ya podemos mostrar el formulario, que está oculto mientras lo estamos construyendo. Esto se hace con GUISetState(@SW_SHOW), en realidad @SW_SHOW es el valor por defecto de esta función, esto quiere decir que lo podemos omitir, GUISetState() hará exactamente lo mismo.
Ahora empieza el bucle principal de gestión de eventos. Típicamente lo que se hace es crear un bucle infinito que comprueba si han llegado mensajes de evento. Sí, infinito, pero AutoIt, y nosotros los programadores, ¡somos tan poderosos que podemos escapar del infinito! Y si no escapamos del infinito es que estamos haciendo algo realmente mal. La verdad es que como veréis es bien fácil, pero eso que quede entre nosotros
Un bucle infinito se hace con una condición de parada... que no pare nunca. Por ejemplo con un "mientras" podemos hacer:
Código: Seleccionar todo
While true
;bloque de instrucciones a repetir
WEnd
Dentro de este bucle "sin fin" lo que hacemos es comprobar continuamente si llega algún mensaje notificando un evento, de aquí el nombre de modo de bucle de mensajes. Preguntamos a AutoIt si ha llegado un mensaje con GUIGetMsg(). Esta función devuelve un valor predefinido para algunos eventos del sistema (como cuando el formulario es cerrado, cambiado de tamaño, maximizado, etc.) así como notificaciones de eventos sobre nuestros controles, por ejemplo cuando el usuario hace clic sobre un botón. En este caso en vez de devolver un valor predefinido lo que hace es decirnos qué control está implicado (por lo que sólo muestra un tipo de evento por control, esta es la limitación de la gestión de eventos de AutoIt que os comentaba cuando explicaba qué es un evento).
El Switch es una forma conveniente de hacer una cosa u otra dependiendo del mensaje que nos llegue, naturalmente se podría hacer lo mismo con una cascada de If-Then-ElseIf..., o con Select, por ejemplo.
Así que si ha llegado un evento proveniente del botón (Case $btnMini) ejecutamos lo que queremos que haga dicho botón, en este caso minimizamos el formulario. Esto se hace con la misma función que usábamos para mostrarlo, pues esta función cambia el estado del GUI según el parámetro que le demos (mostrado, oculto, maximizado, minimizado, etc.). Lo minimizamos con el valor correspondiente para este estado: @SW_MINIMIZE.
Como veis aquí es donde nos es útil haber guardado el botón en la variable $btnMini. Si no lo hubiéramos hecho igual nos notificaría el mensaje cuando se pulsara el botón, ¡pero no podríamos saber que se trata de nuestro botón!.
El siguiente evento que comprobamos es cuando el usuario quiere cerrar el GUI, algo que sólo puede hacer pulsando en el aspa de la barra de título, pues no le hemos puesto un botón de "Cerrar" o similar (vale, también lo puede cerrar con ALT-F4 y también otros métodos menos conocidos, como ESC ). La verdad es que este tipo de eventos puede ser lanzado también por el sistema, por ejemplo si finalizas la aplicación desde el Administrador de Tareas de Windows (pero no si terminas el proceso abruptamente, en vez de finalizar la aplicación).
En ese caso GUIGetMsg() nos devuelve $GUI_EVENT_CLOSE. Cuando esto ocurra lo que hacemos es... ¡salir del bucle infinito!. Esto se hace simplemente con ExitLoop, que sirve precisamente para finalizar al momento el bucle en curso, sea éste infinito o no. En este caso como el programa no tiene más instrucciones para ejecutar después del bucle, simplemente finalizará, que es lo que queremos. En este caso tan simple en vez de salir del bucle también podríamos hacer que finalice directamente el programa con Exit.
IMPORTANTE: Que nos notifiquen el evento no siempre quiere decir que se haya realizado la tarea que le corresponda, precisamente la notificación es para que hagamos dicha tarea, si queremos, ¡ese es nuestro trabajo!.
Es decir, que nos diga que el usuario ha pulsado nuestro "botón de minimizar" no minimiza el formulario, el sistema nos informa de que se ha pulsado ese botón ¡y entonces es nuestro trabajo actuar en consecuencia y minimizar el formulario!
Esto no siempre es tan evidente, si quitamos las dos líneas:
Código: Seleccionar todo
Case $GUI_EVENT_CLOSE
ExitLoop
¡NORMALMENTE EL SISTEMA NOS NOTIFICA LOS EVENTOS, NOSOTROS DEBEMOS RESPONDER A ESOS EVENTOS!
Por conveniencia hay una excepción a esto, aunque es opcional (por defecto está activado), y es que los eventos del sistema de maximizar ($GUI_EVENT_MAXIMIZE), minimizar ($GUI_EVENT_MINIMIZE) y restaurar ($GUI_EVENT_RESTORE) sí son procesados por el sistema. Pero ojo, sólo los eventos del sistema Windows estándar, como los botoncitos de la barra de título, no los de nuestros controles propios como el botón de minimizar de nuestro ejemplo.
Este comportamiento se puede desactivar poniendo la opción GUIEventOptions a uno, (por defecto está a cero):
Código: Seleccionar todo
Opt("GUIEventOptions", 1)
Bien, aquí finaliza este mini-tutorial, espero que os sea útil. No os podéis quejar de lo extensamente explicado que está algo más o menos sencillo, pero como es la base de la gestión de eventos en AutoIt, al menos en el modo MessageLoop, he creído interesante desarrollarlo bastante.
¡Espero que os aproveche!
Ximorro
-----------------
Versión 1.1, 5/08/2010
.- Incluida información sobre GUIEventOptions y el tratamiento especial de los eventos del sistema de minimizar, maximizar y restaurar.
Versión 1.0, 4/08/2010
.- Versión inicial.