| Tutorial de Delphi | ||
De Clipper a Delphi |
¿Qué puedo utilizar en Delphi cuando en Clipper usaba las funciones...?
Array(). La creación de arrays se realiza definiendo la variable como tal
TablaX:array[0..20] of string;
indicando el número de elementos y el tipo de estos. Además, en Delphi se pueden crear listas, tipo TList o TStringList.
AT(). Para conocer la posición de una expresión en una cadena de caracteres se utiliza
Pos(Substr; string)
y devuelve un entero, que será 0 si no está contenida.
BOF (). Marca de inicio de fichero. No varía su sintaxis, pero en Delphi no es una función.
Tabla.bof;
CHR(). Devuelve el valor numérico, según la tabla ASCII, de un caracter. Puede utilizarse la misma función. No obstante, para el uso que normalmente se ha dado en Clipper utilizaríamos la forma #número_de_tecla
'cadena'+chr(13) => 'cadena'+#13
DATE(). Devuelve la fecha del sistema. No hay variación.
DTOC(). Convierte una fecha en una cadena de caracteres.
DatetoStr(fecha);
DOW(). Devuelve un entero indicando el día de la semana .
DayOfWeek(fecha);
EOF(). Marca de final de fichero. La misma sintaxis, pero en Delphi no es una función.
Tabla.eof;
INKEY(). No hay una forma similar en Delphi de detener la ejecución de un programa. Tiene poco sentido en general dado la diferencia de filosofía entre los dos lenguajes. No obstante se puede realizar mediante instrucciones Timer de Windows.
INT(). Devuelve el valor entero de una variable numérica. Funcionan de la misma forma.
LASTKEY(). La obtención de las teclas pulsadas se realiza en Delphi mediante los eventos. No tiene sentido el uso de funciones de este tipo.
LEN(). Devuelve el número de dígitos de una cadena de caracteres o variable alganumérica. En Delphi se utiliza la función length.
Length(variable_string);
LOG(). En Delphi hay dos funciones de logaritmos, Log2 y Log10. Estas funciones matemáticas se encuentran en la unit Math.
LOWER(). Para convertir una cadena a minúsculas puede utilizarse LowerCase, que afecta a caracteres de 7 bits, o AnsiLowerCase para los 8 bits.
AnsiLowerCase(variable_string);
LTRIM(). Para elimiar los caracteres blancos a la izquierda en una cadena se utiliza TrimLeft.
MOD(). Para obtener el resto de una operación se utiliza también Mod de la siguiente forma
i mod j => Devuelve el resto en la division. i div j => Devuelve la parte entera.
STR(). Teniendo en cuenta que el tipo de variables es distinto en los dos lenguajes, para convertir una o variable numérica en una expresión alfanumérica, en Delphi se utiliza InttoStr y FloattoStr. La precisión en decimales se puede realizar mediante la instrucción Format.
variable_string:=InttoStr(variable_integer); variable_string:=FloattoStr(variable_real);
SUBSTR(). La obtención de una parte de una cadena se consigue con la función Copy y similar tratamiento.
Copy(cadena,posición_inicio,número_de_digitos);
TRIM(). Para eliminar los caracteres blancos de una cadena se utiliza la misma función Trim.
VAL(). Con las mismas observaciones que en la función STR(), para convertir una cadena o variable alfanumérica en una expresión numérica se utiliza StrtoInt y StrtoFloat.
variable_integer:=StrtoInt(cadena); variable_real:=StrtoInt(cadena);
FUNCIONES DE FECHAS EN GENERAL. Se obtiene el día, mes y año de una variable tipo fecha con el procedimiento DecodeDate.
DecodeDate(Fecha,Anyo,Mes,Dia);
FUNCIONES SOBRE BASES DE DATOS. La amplitud de Delphi en cuanto a tipos de Bases de Datos a utilizar, las múltiples formas de acceder y las diferencias de filosofía en la programación dirigida a objetos, impide establecer relaciones entre los dos lenguajes.
FUNCIONES ACHOICE() Y DBEDIT(). En Delphi hay diversidad de componentes para realizar estas funciones de tipo browse. Los mas similares podrían ser StringGrid y DBGrid respectivamente, pero su funcionamiento sigue siendo distinto por completo.
FUNCIONES UTILIZADAS EN LAS CLASES DEFINIDAS EN CLIPPER 5.X. Habida cuenta que Clipper no es un lenguaje que soporte la programación orientada a objetos como tal, al contrario de lo que ocurre con Delphi, no hay similitud en cuanto a funciones ni técnica de programación en este aspecto.
¿Qué puedo utilizar en Delphi cuando en Clipper usaba los comandos...?
@..BOX, SAY, GET, TO. Los comandos de este tipo dejan de tener sentido. Las coordenadas en Delphi son propiedades comunes a los objetos y es a través de éstos como se introducen datos, se dibujan marcos o se muestra un texto.
ACCEPT. Los datos se introducen por medio de objetos, como se especifica en el punto anterior. El que hace las veces de este comando o del Get/Read puede ser el TEdit.
BEGIN SEQUENCE. El tratamiento de errores, para este comando en concreto, es similar a la utilización de excepciones, que es el método utilizado en Delphi y que se comenta en la pregunta dedicada al fichero Errorsys.
CANCEL. Para concluir la ejecución de un programa se utiliza Close, siempre que se produzca en la ficha principal, por ej. Form1.Close, o con Application.Terminate.
CLEAR. Dado que el funcionamiento en Delphi es por ventanas (formularios) y no por pantalla completa, no tiene sentido este comando. No obstante, aunque la propiedad Clear es común a algunos objetos, no guarda relación alguna.
ListBox1.Clear;
DO. Aunque en Clipper 5 era un comando obsoleto, se sustituía por las llamadas a funciones del tipo mifuncion(). En Delphi es similar a esta última forma, siempre que se indique el lugar (form) en que se encuentra y éste se localice dentro de la claúsula Uses.
Si la función o el procedimiento se encuentran en el mismo fichero desde el que se les llama, basta con
mifuncion(parámetros);
Si se localiza en un lugar distinto hay que hacer referencia a éste
Uses Unit2; ... form2.mifuncion(parámetros);
FUNCTION, PROCEDURE. Las funciones y procedimientos han de estar definidas antes de su ejecución. Si pertenecen a un form han de incluirse dentro de la definición de éste.
type TForm1 = class(TForm) procedure MiProcedimiento(Sender: TObject);
KEYBOARD. Aunque el funcionamiento es distinto, se puede enviar un caracter manejando los eventos del componente que se está utilizando.
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin key := #72; end;
En este ejemplo, y utilizando el evento KeyPress del componente TEdit, sea cual sea la tecla pulsada la convertimos a la 72.
MENU TO. En lugar de este comando para generar menus, se puede sustituir por TMainMenu, TPopupMenu, etc.
PARAMETERS. El paso de parámetros se utiliza de forma similar a las versiones de Clipper 5.x. La diferencia fundamental estriba en que al definir el procedimiento o función se le debe especificar el tipo de parámetros que va a recibir.
procedure MiProcedimiento(MiVariable:integer); ... MiProcedimiento(12);
RENAME. La sintaxis para cambiar de nombre un fichero es
RenameFile('c:\..\fichero_antiguo','c:\..\fichero_nuevo');
RETURN. Un procedimiento o función está comprendidos entre Begin y end; no obstante se utiliza Return de forma similar a Clipper para devolver el resultado de la función. Si se quiere abortar el proceso antes de su finalización se puede hacer con Exit.
RUN. Para ejecutar un programa externo se utiliza la función ExecuteFile.
STORE. Para asignar valores a variables es necesario declararlas con anterioridad
var Ivar:integer; Svar1,Svar2:String;
e inicializarlas una vez dentro del begin correspondiente.Una variable no inicializada produce una advertencia en compilación, si no está declarada se produce un error.
Diferencias en condicionales.
Condicional IF Estructura simple en Clipper: If <expresion> <instrucciones> EndIf y su equivalencia en Delphi (Pascal): If <expresion> then <instrucción>; // Para una sola instrucción
If <expresion> then begin // Para varias instrucciones
<instrucciones>
End;
Estructura anidada en Clipper:
If <expresion>
<instrucciones>
Else // o ElseIf
If <expresion>
<instruccion>
Else
<instruccion>
EndIf
EndIf
Estructura anidada en Delphi:
if <expresion> then begin
<instruccciones>
end else if <instruccion> then <instruccion>;
Instrucción Case
Estructura genérica en Clipper:
Do Case
Case <condicion>
<intrucciones
Case <condicion>
<instrucciones>
Other
<instrucciones
EndCase
La primera diferencia es que, mientras la condición Case en Clipper puede ser de cualquier tipo, en Delphi
ha de ser ordinal.
Case <expresion> of caso1; caso2; else caso3; end; Un ejemplo simple:
var dia:integer;
begin
dia:=DayOfWeek(date);
case dia of
1:Showmessage('Domingo');
2:Showmessage('Lunes');
3:Showmessage('Martes');
4:Showmessage('Miércoles');
5:Showmessage('Jueves');
6:Showmessage('Viernes');
7:Showmessage('Sábado');
else
Showmessage('Imposible');
end;
end;
Diferencias en bucles.
Bucle While. La estructura de éste en Clipper es
Do While condición_de_entrada
<instrucciones
EndDo
y en Turbo Pascal
while condicion_de_entrada do begin
<Instrucciones>
...
end;
Para varias instrucciones. Si solamente es una instrucción la que se ejecuta en el bucle sería
while condicion_de_entrada do <Instruccción>;
Bucle For
En Clipper:
For variable=inicio_contador to fin_contador
<Instrucciones>
Next
En Turbo Pascal:
For variable:=valor_inicial to valor_final do begin
<instrucciones>
...
End;
Como en el bucle While, si solamente es una instrucción la que se ejecuta sería
For variable:=valor_inicial to valor_final do <instrucción>;
Bucle Repeat
Aunque es frecuente en varios lenguajes, este no está implementado en Clipper.
La diferencia esencial entre un While y un Repeat es que en el primero, antes de entrar en el mismo, ha de cumplirse la condición de entrada, es decir, puede ser que no se ejecute nunca lo contenido en su estructura, mientras que en el bucle Repeat la condición no es de entrada, sino de salida, con lo que al menos una vez han de ejecutarse sus instrucciones.
Su estructura es
Repeat
<instrucciones>
...
Until condición_de_salida
Con la claúsula Break se fuerza la salida de cualquiera de ellos (el Exit de Clipper) y Continue salta al final de la estrutura (tipo Loop).
Manejo de Bases de Datos.
Es éste un apartado en el que establecer comparaciones no tiene sentido.
Si la forma de trabajo de Clipper es a través de ficheros tipo dBase (dbf) y, como mucho, de texto a través de las funciones FOpen(), FRead(), etc., dejando al margen los creados a través de la instrucción Save, la de Delphi es radicálmente distinta.
Si bien se pueden utilizar los ficheros dbf, o los db de la B.D. de Paradox, puesto que ambos son de los mismos fabricantes de Delphi, Borland, la forma de trabajar con ellos no se parece en nada, e incluso en algunos casos, como el de los índices NTX, no se soportan directamente, sino a través de terceros (como Apollo).
La utilización de éstos cara a redes de area local, no tiene ninguna relación, dado que el entorno de Clipper, MS-DOS y las LAN con las que se "entiende" bien, las Novell, no se asemeja a la programación en Windows, sin interpretar por esto que redes como Netware no sean perfectamente posibles con Delphi.
Bajo este punto de vista, el programador que quiera efectuar el transbase desde un entorno a otro sería aconsejable que se olvidase de lo aprendido en este punto.
Además, mencionando únicamente tablas denominadas planas (como dbf), cuando la arquitectura predominante podría pasar a ser la de Cliente/Servidor e incluso múltiples capas (clientes, servidor de aplicaciones, servidor de datos, terminales Web, etc.). En este entorno, Borland ofrece Interbase como gestor de datos, no obstante está abierto a cualquier otra, Oracle, Sql Server, etc.
En principio Delphi ofrece el acceso a Bases de Datos a través de su motor BDE o a través de la arquitectura de sistemas abiertos de Windows, el ODBC (Open Data Base Conectivity), e incluso a través de motores de datos de terceros.
Lo anterior está referido a las posibilidades de acceder a B.D. En cuanto a la forma de programar para conseguir algún resultado de las tablas es también diferente de manera radical. Aquí el sistema es orientado a objetos y además se puede utilizar tanto el lenguaje estandar de Delphi, como el del BDE mencionado o a través de SQL, con dependencia de lo que se utilice o lo que se pretenda conseguir.
Lo mencionado no debe llevar al desánimo, sino todo lo contrario, pues las herramientas de que dispone Delphi son tan amplias que se puede conseguir practicamente cualquier cosa que se pretenda.
Por poner un ejemplo, vamos a suponer que estamos transfiriendo una aplicación hecha en Clipper y dbf's a Delphi.
El punto conflictivo para empezar sería el de los índices, puesto que los NTX no serían reconocibles sin herramientas ajenas, y habría que traspasarlos a formato MDX.
A partir de aquí es simple. A grandes rasgos y aunque hay muchas formas de realizar lo que queremos, podemos hacernos una idea siguiendo estos puntos:
1. Introducir en el BDE la localización de nuestros ficheros, dando de alta lo que se denomina un alias (no confundir con el termino de Clipper del mismo nombre), es decir, un nombre que usaremos en un futuro para referirnos a nuestras tablas.
2. "Pegar" un componente TTable (por ej.) en nuestro formulario, que en sus propiedades nos pedirá principalmente el nombre del alias creado en el punto 1, de los ficheros que se encuentran en esa ruta a cuál nos estamos refiriendo y si queremos incluir indices. Con esta información es suficiente para que si activamos el componente en su propiedad Active hayamos hecho lo mismo que si ponemos en Clipper Use fichero index indice.
3. A partir de aquí podemos utilizar componentes de visualización, como TDBGrid, similar en cualto al resultado y mucho mas facil de utilizar que los TBrowse y los TBColumn de las versiones 5.x de Clipper, con solo unirlo a la tabla mediante un componente de enlace, TDataSource, editar campos mediante TDBEdit, buscar datos con Locate (entre otros), editar con Edit, imprimir mediante las utilidades de Q.Report que vienen incorporadas a partir de la versión 3 de Delphi o C.Report en versiones anteriores, visualizar en forma de gráficos múltiples mediante el TeeChart, y un largo etcétera.
Es cierto que el ejemplo expuesto es quizás el más simple que se puede encontrar, pero perfectamente válido y funcional. La complejidad tiene que surgir, puesto que las posibilidades de acceso a datos son prácticamente ilimitadas, y lo será en relación a lo que se pretenda conseguir.
¿Dónde ha quedado el Errorsys de Clipper?
Pues todo aquello de modificar el fichero de control de errores, recompilarlo con la aplicación, etc. se ha quedado en nada que se le parezca al funcionamiento y detección de errores en Delphi.
La similitud sería mas facil encontrarla en la clase Error de las versiones de Clipper 5.x, en la cual se genera una llamada a ErrorBlock pudiendose desde aquí crear la función propia de control. El "parecido" puede encontrarse en la llamada y en la protección de un bloque de código (no un CodeBlock) mediante la estructura Begin ... Sequence.
Definidos en el fichero de cabecera ERROR.CH se encuentran los códigos que se generan.
Veamos en Delphi. El tratamiento de los errores se efectúa mediante las denominadas "excepciones".
El proceso no es dificil, basta considerar dos tipos de excepciones: las que manda una unidad denominada SysUtils
cada vez que se encuentra con un error en ejecución y las que puede lanzar el usuario ante una eventualidad.
La estructura principal de protección del bloque en este caso es Try ... Finally. Veamos un ejemplo
var f:TForm1;
begin
f:TForm1.Create(Self);
try
f.ShowModal;
finally
F.Free;
end;
En el caso de producirse un error en un punto del bloque Try (en este caso al mostrar el form), inmediatamente abandona la ejecución del bloque y pasa el control a Finally, que liberará la memoria.
Esta es la forma más usual de protección ante errores, la otra estructura utilizada es Try ... Except es menos utilizada, salvo que lo que se pretenda sea manejar las excepciones.
b:=5;
c:=0;
try
a:=b div c;
except
// manejadores de excepción
end;
En un momento cualquiera y dentro del bloque Try se produce un error (en este caso división por cero), inmediatamente se sale y si se ha definido dentro del bloque Except un manejador de errores lo ejecuta. Como no se trata de efectuar un estudio exhaustivo, baste con decir que la estructura sería de este tipo:
try
a:=b div c;
except
on Excepción do
begin
.......
end;
end;
donde Excepción definiría el error que la ha provocado, en este caso EZeroDivide. En otros casos sería mas compleja la detección del error en concreto, y se lograría mediante la herencia de la clase Exception, pero no es ese el tema en este momento.
También se especificaba arriba que el usuario puede lanzar una excepción. Esto se consigue sin mas que ejecutando Raise. La utilidad de ello es muy variada e importante, habida cuenta que permite que con su sola ejecución actúen las estructuras Try anteriores o crear una excepción concreta si se pretende esto.
Como la única pretensión es facilitar el camino a los programadores que proviniendo de Clipper "aterrizan" en Delphi, no parece oportuno profundizar más en estas cuestione, en otras preguntas se tratará con más profundidad.
José Luis Freire