Prevención errores.


El programa funciona bien, hace su trabajo perfectamente. Pero alguien me dijo un día que el usuario era el ser más imprevisible sobre esta tierra, y lo faltaba razón. Si haces un programa tu sabes como funciona y que tipo de datos necesita en cada momento, pero el usuario normal debe leer lo que pone la ventana, y para eso ponemos etiquetas (label), pero siempre hay el de turno que va y mete los datos que no debe. Todo esto viene a que si habéis probado el programa de la alarma todo va bien hasta que se me mete una hora que no es valida, como pueden ser las 25:25, por ejemplo, entonces la rutina de conversión de texto a formato hora se queja. Si el programa lo estas ejecutando desde Delphi primero sale un mensaje de error como el que esta aquí debajo.

Este mensaje no es más que una protesta de la función de conversión de texto a hora (StrtoTime). El sistema queda detenido hasta que no pulses sobre el botón del cuadro, al fin al cabo es una ventana modal, el cual ha sido mostrado por Delphi que es el que esta controlando tu aplicación. Al pulsar tu programa estará detenido y podrás echar un vistazo al código fuente para ver donde esta el error, o ejecutar el programa paso a paso, o indicar que siga. Para ejecutarlo paso a paso pulsa F7, para que continúe normalmente pulsa F9 (mira el menú Run del entorno Delphi). A lo que voy es que, si continuas el programa (pulsando F9) sale otro mensaje, este proviene de la aplicación, y dice algo como el cuadro que está a la izquierda de este texto.

Si compilas (ctrl+f9, o compile en el menú Run de Delphi) y ejecutas el programa desde fuera del entorno de Delphi (localízalo con el explorador de Windows, normalmente suele estar en el directorio Bin dentro del directorio de Delphi), solo te saldrá el segundo mensaje ya que es el que proviene de la aplicación que esta corriendo sola (sin la intervención del Delphi). Un consejo es que guardes el proyecto y sus ficheros en un directorio antes de compilar, así el ejecutable se creará en ese directorio. Todo eso está muy bien, pero si a un usuario le sale ese mensaje y encima no tiene ni idea de inglés, en lo primero que se va acordar es en la madre del programador. La solución estaría en que el programa controle el error, y dependiendo del tipo de este pues que saque un mensaje más amigable o incluso que no muestre nada y que sea el propio programa el que corrija el error, todo depende del tipo de error.

En nuestro caso podemos sacar un mensaje diciendo que la hora indicada no es correcta y que la hora de la alarma no será ajustada ni activada. Para controlar estos errores tenemos a muestra disposición unas palabras reservadas que son Try, Except. El sistema funciona según la siguiente filosofía. La instrucción que está debajo de la palabra Try se ejecuta, y si genera alguna excepción se ejecutará la orden que esta debajo de Except. En el caso que no ocurra ningún error la instrucción que está debajo de Except es omitida. Si quieres poner más de una instrucción asociada a una de estas palabras debes delimitarla por un bloque Begin End.

En nuestro programa tenemos estas líneas en el procedimiento de llamada al formulario que usábamos para ajustar la hora.
procedure TForm1.Button1Click(Sender: TObject);
begin
If Form2.ShowModal = MrOk Then
Begin
Hora :=(StrToTime(Form2.MaskEdit1.Text));
Label4.Caption := (Form2.Maskedit1.Text);
Application.Title := Titulo +':'+ TimeToStr (hora);
End;
end;

Si observas las tres primeras líneas después del begin del If, veras que la primera es la que convierte los datos, y es la que genera una excepción en caso de que tenga algún error los datos. Las otras dos son consecuencia de la anterior, o sea, con los datos ya convertidos por la línea anterior realizan una serie de operaciones suponiendo que la conversión de datos ha tenido éxito. Pero como he comentado antes, eso no siempre es así. Entonces la solución esta en las instrucciones Try Except. Entonces meto esas tres instrucciones en un bloque debajo de Try, con lo que me aseguro que si una de ellas genera una excepción el bloque de instrucciones será abandonado quedando sin ejecutar las siguientes instrucciones. De hecho la primera instrucción es la única que puede generar un error.
El motivo que meta las otras dos instrucciones en el mismo "saco" es que me no tiene sentido que se ejecuten si la primera ha fallado. Y solo queda poner una instrucción para cuando se genere el error, yo he puesto un mensaje. El código queda al fina así:
procedure TForm1.Button1Click(Sender: TObject);
begin
If Form2.ShowModal = MrOk Then
Begin
Try
Begin
Hora :=(StrToTime(Form2.MaskEdit1.Text));
Label4.Caption := (Form2.Maskedit1.Text);
Application.Title := Titulo +':'+ TimeToStr (hora);
End;
Except
ShowMessage ('La hora introducida no es correcta'+chr(13)+ 'Los datos no se admiten');
end;
End;
end;

Ten en cuenta que si ejecutas el programa tal como esta desde Delphi, y se genera una excepción Delphi seguirá generando su mensaje de error, ya que al ejecutarse la aplicación desde Delphi este la está controlando, si pulsas F9 para continuas con la aplicación saldrá tu mensaje. Lo que ocurre es que cuando ejecutas el programa desde el entorno de Delphi este sé esta ejecutando subordinado a Delphi, el algo así como si Delphi ejecutara línea a línea tu código y supervisará todos las acciones y reacciones de tu programa. Si ejecutas el programa desde fuera del Delphi, lo que obtendrás, en caso de una excepción, es el mensaje que hemos puesto.

Esto que acabas de aprender es más importante que la función que esta haciendo aquí, que es la de mostrar un mensaje. Sino imagínate que un dato que es recogido y no es correcto, y luego es procesado en cientos de operaciones, más adelante. Si se produce una excepción y no tomamos medidas Dios sabe, que estaremos procesando, puede ser el valor que había antes, o uno que se acaba de sacar el programa de la manga. Quizás lo más lógico sea pensar que es el valor anterior que tenia la variable (como ocurre en este programa), pero quizás en tu supuesto programa no puedas tener valores repetidos, o quizás... Si nos ponemos a suponer no acabamos nunca, y lo mejor en programación es atar todos los cabos y no dejar nada al azar informático.