Alarma Despertador.

El programa que se me ha ocurrido hacer es una alarma. El programa en si no es una alarde de programación pero me servirá para introducir algunos controles nuevos, y usar lo aprendido hasta hoy, así como puede servir como plataforma para hacer experimentos. Coloca un formulario y retoca las propiedades según indico continucación:
BorderIcons.biMaximize = False
BordeStyle = BsSingle
Ten en cuenta que cuando pongo BorderIcons.biMaximize, significa que la propiedad biMiximize está dentro de la propiedad BorderIcons, por lo tanto tendrás que desplegar su contenido en el inspector de objetos.

Pantalla principal

Coloca cuatro etiquetas, Label1 será la que muestre constantemente la hora actual, y label4 la hora a la cual está fijada la alarma. Las otras dos son para indicar que es cada cosa. Mira la imagen capturada de mi escritorio a la derecha de este texto.Te comento lo de label1 y label4, porque mi código fuente, así como este texto harán referencias a ellas. También coloca un par de botones, uno de ellos servirá para ajustar la alarma, y el otro para cerrar la aplicación. Así que en uno de ellos pon en su propiedad Caption el texto: Alarma, y en el otro Salir. Ahora viene algo nuevo. Fíjate en ese control que tiene un reloj en el centro, se llama Timer, y lo encontras en la paleta System. Este control permite generar un evento cada cierto tiempo, sitúa uno en el formulario y observa sus propiedades. De las pocas que tiene las dos importantes son: enabled e interval. La primera sirve para activarlo, la segunda es el intervalo cada cual ejecuta un evento, ahí pon 1000, ya que queremos generar un evento cada segundo, y las unidades de esta propiedad son milisegundos. Mira la página de eventos del timer, ¡solo hay uno!, Y es el único que necesitamos. Siempre que pase un segundo se ejecutará el código contenido en ese evento.

He dejado para el final, el control que está marcado entre los cuadrados en la imagen capturada de mi escritorio. La verdad es que está así adrede. Es otro control nuevo, se llama CheckBox, y esta en la paleta Standard, es ese que tiene por dibujo un cuadrado con una cruz dentro. Colócalo en el formulario, y en propiedad Caption (como no), pon el texto alusivo a su función. Este control tienen más propiedades, míralas, y fíjate que hay muchas comunes con otros componentes. Esto es algo bastante común en Delphi, lo cual es una ventaja, ya que solo hay que saberse las propiedades especificas de cada control. De todos modos si tienes una duda, pon el cursor dentro de una propiedad como si fueses a cambiarlas, y pulsa la tecla F1, y Delphi amablemente mostrará una ayuda sobre el tema. Como todo control que cambia su aspecto o realiza una acción al ser pulsado (como los botones, por ejemplo), pues tiene un evento Onclik asociado, el cual usaré para cambiar el titulo de la aplicación. Así cuando se produzca una pulsación del ratón sobre el componente analizaré su estado, y en consecuencia tomaré una decisión. Acabo de introducir la característica más importante del esta componente al decir que analizaré su estado. De hecho es la razón de su existencia. Un CheckBox puede tener dos estado, entendiendo por estado el aspecto que adopta. CheckBox tiene dos estado, uno cuando esta con una cruz en su interior, y otro estado cuando no tiene nada, o sea cuando esta marcado. Este estado está definido por la propiedad Checked. Así cuando esta con la cruz su propiedad Checked es igual a True. Para que te hagas una idea sobre el control, CheckBox, es esa clásica casilla de los exámenes tipo test, donde debes una marcar para decir que esa es la contestación buena.

Ahora vamos a crear otro formulario en el cual se nos dará la opción de ajustar la alarma. Para empezar un nuevo formulario, y en la propiedad BordeStyle iguálala a bsDialog, ya sabes porque (mira el capitulo anterior si tienes dudas), y ponle algo significativo como titulo. Coloca un par de botones del tipo BitBtn, uno para aceptar los cambios y otro para recharlos. Una etiqueta para indicar a que hora esta programada la alarma, y otra que indique algo significativo sobre que es la etiqueta anterior. Hecha una mirada a la imagen capturada. Fíjate en ese cuadro que tiene que dos rayas dentro de él. Se llama Maskedit, y es el protagonista de este formulario, lo encontras en la paleta Additional. Es un cuadro de Texto (valla no os he contado nada sobre los cuadros de texto), el cual nos permite introducir una serie de números y/o letras, pero con la peculiaridad de que los datos introducidos deben estar en consonancia con lo que indica el cuadro. Así este cuadro lo podemos configurar para que solo acepte cuatro números, separados por dos puntos. Valla en pocas palabras para que acepte la hora como si fuese un reloj digital. Pulsa dos veces sobre su propiedad EditMask y verás un cuadro de Diálogo donde te permite introducir una mascara, según la cual se introducirán los datos. Puedes crear tus propias mascaras (en la ayuda tienes la claves) poniendo diversos caracteres, o lo más rápido es seleccionar una ya hecha y que se ajuste a nuestras necesidades. Así que míralas y fíjate que la que necesitamos es ShortTime.

Bueno, pues ya queda poco. Pero antes un puntualización, quizás los más avispados se hayan dado cuenta que los dos formularios tienen unas etiquetas que muestran la hora a la cual está fijada la alarma. Bueno pues es muy fácil. Declaro una variable que contenga la hora a la que esté programa la alarma, y que esté disponible para ambos formularios. Así que la pongo en la sección Public del formulario, así está disponible para todos los formularios que hagan referencia en su cláusula uses al formulario principal. Fíjate que es del tipo TdateTime, eso es porque en ella vamos a almacenar un dato que representa una fecha y una hora, aunque nosotros solo usemos la parte de la hora. Si mirás el código un poco más abajo esta la sección Private del Formulario, en esta sección declaramos las variables que queremos que estén disponibles para todos los procedimientos y funciones de este y solo este formulario.

La Trampa de este programa esta en el evento OnTimer. En él está el "puente de mando" del programa ya que una alarma gira entorno a la hora que es. Así este evento se genera cada segundo, y nada más entrar en el transformamos la hora actual que esta contenida en la variable Timer, la cual no hemos declarado porque es un valor que nos da el sistema, en formato cadena de caracteres que es lo único que puede representar una etiqueta (label1 en este caso).
Luego decodificamos la hora a la cual esta la alarma, y digo decodificar, porque Delphi almacena la fecha y la hora en un único número, y una parte de él es la fecha, otra la hora, otra los minutos, y así sucesivamente. No tiene mucho sentido explicar el formato de este número, porque si nos interesa saber que hora es, hay una función que nos hace el trabajo sucio. La función es DecodeTime, (existe, también, DecodeDate, para la fecha), donde el primer parámetro es la hora en formato Delphi, y los sucesivos son la hora, los minutos, los segundos, y los milisegundos, en los cuales Delphi devolverá la hora. Decodificamos la hora actual con el mismo sistema, y comparamos la hora actual con la hora de la alarma, lo mismo con los minutos, y comprobamos si el control CheckBox esta marcado, si se dan las tres condiciones (el operador And, es un i lógico) es la hora, así que desactivamos el CheckBox, y hacemos sonar un sonido con una función propia de Windows, mostramos un aviso, y cuando se cierra el aviso, paramos el sonido.

El truquillo de este capítulo es la función Sndplaysound, la cual es una función de windows (una Api). Para llamarla solo tienes que pasarle el nombre del fichero de sonido, y luego un parámetro que determina la manera actuará la función con respecto a nuestro programa. Si el fichero no se encuentra, por defecto, sonará el sonido por defecto del sistema. La función retorna True, o False según el éxito que haya tenido.

SND_ASYNC: La función retorna el control a nuestro programa después de que empezara el sonido.
SND_LOOP: El sonido es ejecuta una y otra vez hasta que es llamada la función de nuevo sin ningún parámetro en el nombre del fichero. Lo que es el caso del ejemplo.
SND_MEMORY: El nombre del fichero indica un fichero en memoria (no sé como se puede hacer!).
SND_NODEFAULT: Si el fichero indica no se encuentra el sistema no genera el sonido por defecto
SND_NOSTOP: Si un fichero esta sonando, la función devuelve False, sin tocar el sonido que se especifico en la llamada.
SND_SYNC: La función no retorna el control hasta que el sonido acaba de ejecutarse.
Acuérdate de añadir la cláusula Mmsystem en la línea uses del formulario, para poder acceder a los servicios de esta Api. El motivo de que me guste el Delphi la tiene su facilidad para usar la programación a bajo nivel en windows, un ejemplo muy claro es esta función. Ese es uno de mis grandes vicios, programar a bajo nivel, y si es sencillo que más se le puede pedir.