Boletín Pascal #26 - 05-SEP-2001
INDICE
1. UNAS PALABRAS DEL EDITOR
- Se necesita ayuda
2. DELPHI ADENTRO (y II)
- La historia de una instancia que aún no era instancia
- Mecanismo de llamada a los métodos estáticos
- Mecanismo de llamada a los métodos virtuales
- Unas palabras finales
- Referencias bibliográficas
- Glosario
3. CONSTRUYENDO UN OBJETO DE NEGOCIO
4. PREGUNTAS FRECUENTES SOBRE DELPHI 6 PERSONAL EDITION
- ¿Por qué la llamaron "Personal"?
- ¿A quiénes está dirigida?
- ¿Es gratis?
- ¿Si es gratis, por qué Borland la vende?
- ¿Es código abierto ("open source")?
- ¿Tengo que distribuir mis aplicaciones bajo la GNU GPL?
- ¿Qué componentes vienen con la Edición Personal?
- ¿Hay una Edición Estándar de Delphi 6?
- ¿Cómo instalo Delphi 6 Personal?
5. COMPONENTES VCL
- Componente SpeedParser - Analizador Rápido de Expresiones
- Imagen PCX con soporte de paleta
6. TRUCOS Y CONSEJOS
- Haciendo una aplicación cliente TCP/IP - Compartiendo mi
experiencia...
· Conectándose a un servidor TCP/IP desde un cliente Delphi
· La solución que encontré es...
- Alineando texto en un StringGrid
- Evitando que el usuario ejecute otras aplicaciones
7. DELPHI EN LA RED
________________________________________________________________________
1. UNAS PALABRAS DEL EDITOR
En esta edición me complace presentar la segunda (y última) parte del
artículo Delphi Adentro de Víctor Lorenzo Prado. También me alegra
darle la bienvenida a nuevos autores en este boletín, como Max Kleiner,
Mattias Andersson, Tommy Andersen y S.S.B. Magesh Puvananthiran.
También me complace anunciar que el foro delphi-intermedio (nuestro foro
para programadores en Delphi) ha superado los 300 miembros y ha
alcanzado un promedio de catorce mensajes diarios. Lo invito a que vea
los últimos mensajes y compruebe que sus miembros hacen un gran esfuerzo
por no dejar preguntas sin contestar:
http://espanol.groups.yahoo.com/group/delphi-intermedio/messages
Para unirse al foro, puede hacerlo desde la web:
http://espanol.groups.yahoo.com/group/delphi-intermedio/join
O por email:
delphi-intermedio-subscribe@gruposyahoo.com
Puede configurar su suscripción al foro para convertir o no los mensajes
a formato HTML, o para no recibir los mensajes en su email (podrá ver
los mensajes en la web).
Se necesita ayuda
=================
Por más de un año, cada edición del boletín ha sido el trabajo de un
solo individuo. Desde la edición pasada, estoy agradecido de contar con
la colaboración de Matthew J. Brock, quien desinteresadamente ha hecho
una revisión del texto de la edición en inglés. Esta ha sido una buena
experiencia, y ahora quisiera hacer un llamado para otras posiciones:
Compatibilidad de versiones de Delphi: Este sería un equipo de programa-
dores Delphi que usen diferentes versiones del compilador. Su trabajo
sería probar los ejemplos de código de los artículos para determinar
si funcionan en su versión, y si no, portarlos si es posible.
Traductores inglés-español: Su trabajo sería traducir el texto de los
artículos originalmente escritos en inglés. Se trataría que la traduc-
ción se realice a un español latinoamericano neutro.
Traductores español-inglés: idem ant., pero del español al inglés
para la edición en inglés.
Editor: Sí, ése es mi puesto, no está vacante todavía, pero quizás lo
esté en un futuro cercano. El trabajo del editor es manejar parte de
las relaciones con los autores, juntar las piezas y escribir la nota
del editor. Se requiere gran dominio del inglés (lecto-escritura).
Aunque estos trabajos quizás no signifiquen mucho más que un par de
horas a la semana, el requisito para todas las posiciones es un nivel
más o menos alto de disponibilidad (como media hora por día o más)
porque, como usted podrá imaginarse, el boletín se hace en "cadenas"
de pequeñas partes...
Esto es todo trabajo voluntario, no existe ninguna remuneración por él
excepto por la satisfacción de ayudar divulgar el conocimiento sobre
Delphi y figurar en los créditos como parte del staff del boletín. Si
está interesado, por favor no dude en ponerse en contacto conmigo y no
se olvide de mencionar la/s posiciones a las que aspira y por qué desea
ocuparlas.
Saludos,
Ernesto De Spirito
eds2008 @ latiumsoftware.com
________________________________________________________________________
JfControls Lib. Multilenguaje. Multiapariencia. Skins. Privilegios. Más
de 40 componentes integrados y personalizables. Múltiples problemas de
programación resueltos. Administración centralizada de recursos. Para
Delphi 3-2006 y C++ Builder 3-6. http://www.jfactivesoft.com/spindex.htm
________________________________________________________________________
2. DELPHI ADENTRO (y II)
Por Víctor Lorenzo Prado <vlorz@yahoo.es>
La historia de una instancia que aún no era instancia
=====================================================
En la sección anterior se introducían algunos conceptos básicos sobre
teoría de la programación, de gran utilidad para el desarrollador de
software profesional. Se planteaba como una necesidad el abstraerse de
la estructura interna de las clases, de su implementación. En esta
sección, en cambio, se propone el "Abstraernos un poco de las Abstrac-
ciones" para comprender un poco más sobre la operación de las clases en
Delphi.
Comencemos por analizar las causas que originan un error muy común
cuando se programa en Delphi (la realización de llamadas a métodos de
una instancia, o el acceso a sus propiedades, cuando esta aún no ha sido
inicializada) y que nos ayudará a comprender un poco sobre las interio-
ridades de su compilador.
Tomemos como caso de estudio la declaración e implementación de la clase
"TSampleClass" que se brinda en el Listado 1:
Listado 1. Clase TSampleClass.
------------------------------
Interface
Type
TSampleClass = Class
Protected { Declaraciones Protegidas }
{ Campos Privados (Datos) }
FProperty1 : integer;
FProperty2 : integer;
{ Métodos de acceso a propiedades }
procedure SetProperty2(const Value: integer);
function GetProperty2 : integer;
Public { Declaraciones Públicas }
{ Métodos Públicos }
function VirtualFunction1 : integer; virtual;
function StaticFunction1 : integer;
{ Propiedades Públicas }
Property Prop1 : integer read FProperty1 write FProperty1;
Property Prop2 : integer read GetProp2 write SetProp2;
End; { TSampleClass }
Implementation
{ TSampleClass }
procedure TSampleClass.SetProperty2(const Value: integer);
begin
{ Asigna el valor a la propiedad }
FProperty2 := Value;
end;
function TSampleClass.GetProperty2: integer;
begin
{ Devuelve el valor de la propiedad }
Result := FProperty2;
end;
function TSampleClass.StaticFunction1: integer;
begin
{ Solo devuelve un 0 }
Result := 0;
end;
function TSampleClass.VirtualFunction1: integer;
begin
{ Solo devuelve un 0 }
Result := 0;
end;
(Nota: Por simplicidad ha sido eliminado el resto del código
que conforma la Unit)
(-------- Fin del Listado 1 --------)
Analizando el listado vemos que se está declarando una clase que posee
dos propiedades, "Prop1" y "Prop2", ambas de tipo "Entero Con Signo de
32 bits" (integer):
{ Propiedades Públicas }
Property Prop1 : integer read FProperty1 write FProperty1;
Property Prop2 : integer read GetProp2 write SetProp2;
Puede observarse que el acceso al contenido de la propiedad "Prop1" se
realiza directamente mediante lecturas y escrituras en el campo
"FProperty1"; y a la propiedad "Prop2", mediante los Métodos de Acceso
a Propiedad "GetProp2" (lectura) y "SetProp2" (escritura).
Además de estas dos propiedades, la clase también exporta dos métodos:
{ Métodos Públicos }
function VirtualFunction1 : integer; virtual;
function StaticFunction1 : integer;
En su implementación ambos métodos realizan la misma función, devolver
como resultado un valor nulo (cero). Sin embargo algo curioso ocurre con
ellos, no se comportan de igual manera cuando son llamados para una
instancia que no ha sido aún "creada" (instanciada, se suele decir).
Veamos el experimento que se muestra en el código de programa del
Listado 2:
Listado 2. Llamadas a los Métodos sin Instanciar la Clase.
----------------------------------------------------------
function TDelphiAdentro_II.TestMethodsCalls_1 : integer;
var
SampleClass : TSampleClass;
i : integer;
begin
{ Note que se realizan la llamadas
sin inicializar la instancia }
i := SampleClass.StaticFunction1 + 5;
Result := i + SampleClass.VirtualFunction1;
end;
(-------- Fin del Listado 2 --------)
Dando una mirada al código debe esperarse que esta función devuelva como
resultado el valor entero 5 ("SampleClass.StaticFunction1" debe retornar
0, que sumado con 5 da como resultado 5, que sumado a su vez al
resultado de "SampleClass.VirtualFunction1", también cero, debe entonces
resultar en un valor 5). ¡¡Pero no ocurre así!!
Si esta función es ejecutada paso a paso podrá apreciarse que, en
efecto, "SampleClass.StaticFunction1" devuelve 0, ¡¡Pero la función
"SampleClass.VirtualFunction1" No!! En lugar de devolver un valor 0 esta
función provoca un Error Fatal de Violación de Acceso:
Access violation at address 00402DD4 in module 'T4C.exe'.
Read of address C08BC300.
¿Por qué ocurre esto si las dos funciones son "exactamente" "iguales"?
Ah..., porque simplemente no lo son, el método "VirtualFunction1" es
declarado virtual, mientras que el método "StaticFunction1" es estático.
Y esto hace que los mecanismos implementados por Delphi para tener
acceso a ellos (mecanismos de llamada, uso de la instrucción CALL del
microprocesador) sean totalmente distintos.
Mecanismo de llamada a los métodos estáticos
============================================
Comencemos por ver el funcionamiento de las llamadas a métodos estáticos
a partir de observar qué sucede al compilar el fragmento de código dado
en el Listado 3.
Listado 3. Llamadas al Mismo Método en Distintas Instancias.
------------------------------------------------------------
procedure TDelphiAdentro_II.TestMethodsCalls_2;
var
{ Declaración de Variables Locales }
SampleClass1 : TSampleClass;
SampleClass2 : TSampleClass;
i : integer;
begin
try
{ Creación de las Instancias de la Clase }
SampleClass1 := TSampleClass.Create;
SampleClass2 := TSampleClass.Create;
{ Llamadas a los Métodos }
i := SampleClass1.GetProperty2;
i := SampleClass2.GetProperty2;
Result := i;
finally
{ Destrucción de las Instancias }
SampleClass1.Free;
SampleClass2.Free;
end;
end;
(-------- Fin del Listado 3 --------)
Obsérvense las secciones que posee este fragmento de código: una primera
de declaración de las Variables Locales (dos para las instancias de la
clase TSampleClass y un entero); una segunda donde son creadas las
instancias de la clase (sobre este particular se tratará un poco más
adelante); una tercera donde es invocado, para dos instancias distintas
de la misma clase, el método "GetProperty2"; y una cuarta de liberación
de la memoria ocupada por las instancias.
Lo interesante de este código está en observar la implementación del
método "GetProperty2" de la clase "TSampleClass", dado en el Listado 1,
y la forma utilizada en el Listado 3 para invocarlo. Si aparentemente no
se le está pasando ningún parámetro al método ¿Cómo puede entonces
"saber" el código de programa dónde están los datos con que debe operar?
Partiendo de lo planteado en la primera parte sobre la encapsulación en
un mismo ente de los datos y los métodos de procesarlos, pudiera alguien
pensar en que para cada instancia que se crea de la clase, junto con el
espacio de los datos, se incluye otro para copiar el código que los debe
procesar. Pero de hacerlo así sería un craso error, un total desperdicio
de recursos.
Momentáneamente pudiera parecer un "enigma", pero la solución utilizada
para resolver este problema técnico es en extremo sencilla: Enviar como
primer parámetro un apuntador a la zona que contiene los datos de la
instancia. ¿Que este parámetro no aparece declarado en la interfaz del
método? Es cierto, no aparece, precisamente ahí se está aplicando el
paradigma de la abstracción sobre la implementación de los mecanismos
que hacen operar a las clases. Pero ese mecanismo no queda del todo
oculto para el programador, no aparece en la declaración de la interfaz
(¡Genial, menos código que escribir!) pero sí se puede tener acceso a él
mediante el parámetro "Self". El parámetro "Self" no es otra cosa que un
apuntador a la instancia de la clase.
Veamos cómo funciona esto a nivel del código ensamblador que genera el
compilador para la sección donde son invocados los métodos:
{ Sentencia }
i := SampleClass1.GetProperty2;
{ Código Generado }
MOV EAX,[EBP-$04]
CALL TSampleClass.GetProperty2
MOV [EBP-$0C],EAX
{ Sentencia }
i := SampleClass2.GetProperty2;
{ Código Generado }
MOV EAX,[EBP-$08]
CALL TSampleClass.GetProperty2
MOV [EBP-$0C],EAX
El código es autoexplicativo, aún para los no habituados al lenguaje
ensamblador de 32 bits. Hagámosle una disección:
* Sentencia que escribimos en Delphi:
i := SampleClass1.GetProperty2;
* Preparación del primer parámetro con la dirección
donde se encuentran los datos de la instancia:
MOV EAX,[EBP-$04]
* Llamada al código de programa correspondiente al método:
CALL TSampleClass.GetProperty2
* Almacenamiento del resultado devuelto:
MOV [EBP-$0C],EAX
Dado que las variables que se han declarado son locales a un
procedimiento, el espacio para ellas es reservado dentro del STACK, de
aquí que EBP-$04 contenga el apuntador (dirección) a los datos de la
instancia "SampleClass1"; EBP-$04, a los de "SampleClass2"; y EBP-$0C,
el valor de "i".
Comenzamos primeramente por un método estático que no toma parámetros de
entrada por su simplicidad. Pero aún si el método tomara parámetros el
mecanismo sería igual, el primer parámetro sería un apuntador a los
datos de la instancia y luego el resto de los parámetros.
Visto esto, ya se nos presenta a la vista la respuesta del porqué cuando
se llamaba al método "StaticFunction1" en el experimento del Listado 2
no ocurría ningún error. ¿Cierto? No había lugar a errores porque no se
hacía acceso a ningún campo de la instancia, pero si se hubiera tenido
acceso a alguno de sus campos sí hubiera habido errores. Pruebe, por
ejemplo, a ejecutar paso a paso la siguiente línea de código observando
las instrucciones en lenguaje ensamblador generadas por el compilador:
i := TSampleClass(nil).GetProperty2;
En este caso, el método "GetProperty2" provocará un error de violación
de acceso al tratar de tener acceso al campo "FProperty2".
Nótese ahora un detalle importante en el código generado por el
compilador para la llamada a un método estático, la instrucción de
llamada utilizada es de tipo directo:
CALL TSampleClass.GetProperty2
"TSampleClass.GetProperty2" representa la dirección donde se encuentra
el código que implementa el método "GetProperty2". Esto es posible
porque, para los métodos estáticos, conociéndose la clase a la que
pertenece la instancia ya se conoce exactamente la dirección donde
radica el código que los implementa.
*** PARA LOS MÉTODOS ESTÁTICOS, EL TIPO (CLASE) DECLARADO PARA LA
VARIABLE QUE CONTENDRÁ LA INSTANCIA ES QUIEN DETERMINA CUALES SERÁN LOS
MÉTODOS LLAMADOS Y NO EL TIPO DE LA CLASE QUE HA SIDO INSTANCIADA ***
Mecanismo de llamada a los métodos virtuales
============================================
Antes de explicar el mecanismo de llamada a los métodos virtuales de una
instancia es válido recordar un concepto, la POO no es únicamente
ENCAPSULACIÓN de datos y métodos de procesamiento en un mismo ente,
también es POLIMORFISMO, y los métodos virtuales son precisamente los
que permiten su existencia. Mediante el empleo de métodos virtuales
podemos crear clases con iguales interfaces y comportamientos distintos,
donde el comportamiento de la instancia de la clase sea determinado por
la clase que ha sido instanciada y no por el tipo declarado para la
variable a la que se asigna la instancia [1].
El mecanismo utilizado por Delphi para implementar las llamadas a los
métodos virtuales utiliza el mismo modo de pasar la información sobre la
instancia a la cual se invoca el método. Pero difiere en la forma de
realizar la llamada. Dado que el método a llamar depende de la clase que
ha sido instanciada (posiblemente desconocida en tiempo de compilación)
y no del tipo declarado para la variable que almacena la instancia, el
método de llamada no puede ser de forma directa.
La solución encontrada para este problema es también relativamente
simple: El uso de una Tabla de Métodos Virtuales (VMT), una tabla donde
son almacenadas las direcciones de los métodos virtuales asociados a la
clase de la cual se ha creado la instancia.
¿Es necesario que cada instancia posea su propia copia de la tabla de
métodos virtuales? No, basta con que exista solo una tabla de métodos
virtuales asociada a la clase y que la instancia "conozca" dónde
localizarla. Y lo más simple es, al crear la instancia, colocar la
dirección de la tabla de métodos virtuales en forma de puntero en uno de
sus campos.
Tomemos nuevamente como material de estudio un fragmento de código,
ahora el dado en el Listado 4:
Listado 4. Llamadas al Mismo Método en Distintas Instancias.
------------------------------------------------------------
function TDelphiAdentro_II.TestMethodsCalls_3 : integer;
var
{ Declaración de una Variable Local }
SampleClass1 : TSampleClass;
begin
try
{ Creación de una Instancia de la Clase }
SampleClass1 := TSampleClass.Create;
{ Llamadas al Método de una instancia inicializada }
Result := SampleClass1.VirtualFunction1;
finally
{ Destrucción de la Instancia creada }
SampleClass1.Free;
end;
end;
(-------- Fin del Listado 4 --------)
Veamos entonces el código generado por Delphi para tener acceso a un
método virtual:
{ Sentencia }
Result := SampleClass1.VirtualFunction1;
{ Código Generado }
MOV EAX,[EBP-$08]
MOV EDX,[EAX]
CALL DWORD PTR [EDX]
MOV [EBP-$04],EAX
Nuevamente el código es autexplicativo, pero hagámosle también una
disección:
* Sentencia que escribimos en Delphi :
Result := SampleClass1.VirtualFunction1;
* Preparación del primer parámetro con la dirección
donde se encuentran los datos de la instancia:
MOV EAX,[EBP-$08]
* Obtener la dirección de la tabla de métodos virtuales:
(puntero almacenado en el primer campo de datos de la instancia)
MOV EDX,[EAX]
* Llamada al código de programa correspondiente al método:
(Primera entrada dentro de la tabla de métodos virtuales)
CALL DWORD PTR [EDX]
* Guardar el resultado en una variable temporal en el STACK:
MOV [EBP-$04],EAX
Y ahora, una vez visto este código se puede llegar a otra conclusión
importante:
*** PARA INVOCAR UN MÉTODO VIRTUAL DE UNA INSTANCIA ES NECESARIO TENER
ACCESO A UNO DE SUS CAMPOS, LA VMT, Y POR LO TANTO NO SE PUEDEN INVOCAR
MÉTODOS VIRTUALES DE UNA INSTANCIA SI ESTA AÚN NO HA SIDO CREADA ***
Esta es la causa del error que se nos presenta cuando ejecutamos el
código del experimento del Listado 2.
Para conocer más detalles sobre el funcionamiento de la tabla de métodos
virtuales y su estructura puede consultarse el material que Inprise
brinda en [2].
Unas palabras finales
=====================
¿Se les ocurre ya cómo crear métodos que "generalmente" no "exploten"?
Imagino que sí, pero les daré una pista... ¿Han visto que el método
"Free" de los descendientes de "TObject" casi "nunca" explota? Échenle
un vistazo a su código, que es tan interesante como sencillo.
Moraleja de la Historia: ¿Cuál es la diferencia entre una Instancia de
una Clase y un Balón de Football? Que podemos imaginarnos que tenemos un
balón rodando frente a nosotros y pretender que le pateamos y damos un
gol, y hasta escuchar la algarabía de los hinchas. No importa lo fuerte
que le pateemos nadie saldrá herido ni ninguna ventana rota. Podremos
simular que jugamos con él si queremos. Pero en el caso de la instancia
no podemos jugar demasiado con la imaginación, porque si no existe sí
podremos "romper alguna ventana de cristal" y en lugar de aplausos
recibir como pago un bien desagradable cartel de Windows diciendo
"Access Violation...bla bla bla".
Referencias bibliográficas
==========================
[1] - Inprise Corporation, "Virtual and Dynamic Methods", Object Pascal
Reference (incluido dentro de las ayudas en línea), 1999.
[2] - Inprise Corporation, "Virtual Method Table", Object Pascal
Reference (incluido dentro de las ayudas en línea), 1999.
Glosario
========
CALL - Instrucción del microprocesador. Llamada a Subrutina. Permite
ejecutar bloques de código que realizan funciones que son comunes
a varias partes del programa sin tener que repetirlos.
ERROR FATAL DE VIOLACIÓN DE ACCESO - Error que ocurre cuando una
aplicación trata de tener acceso a un recurso reservado para otra
aplicación o para el propio sistema operativo.
INSTANCIAR - Crear una instancia de una clase. Reservar dinámicamente el
espacio de memoria necesario para almacenar sus campos y el resto
de los datos que permitirán su operación mediante una llamada al
constructor de la clase.
STACK - Estructura de datos utilizada por los microprocesadores para
salvar momentáneamente el contenido de los registros y luego poder
restaurarlos al terminar de trabajar con ellos. Funciona según una
lógica "First-In Last-Out" (el primero en entrar es el último en
salir). El STACK también es utilizado por los programas para el
pase de parámetros a subrutinas y para la creación de variables
locales.
VMT - Del inglés Virtual Method Table. Tabla de punteros donde se
almacenan las direcciones asociadas a los métodos virtuales de una
instancia de una clase.
________________________________________________________________________
3. CONSTRUYENDO UN OBJETO DE NEGOCIO
- Por Max Kleiner http://max.kleiner.com
"UML mit Delphi" ca.370 S., Precio: 40.85 EUR, ISBN-3935042000
¿Qué es un objeto de negocio?
-----------------------------
Para proporcionar servicios de negocio, un objeto de negocio trabaja en
colaboración con los objetos de almacenamiento de datos y los objetos de
interfaz. Un objeto de negocio transforma los datos en información con
consultas o cálculos. Los datos se pueden obtener de los servicios de
datos o de los servicios de archivo.
Los objetos de negocio a veces son referidos como objetos conceptuales,
porque proveen servicios que cumplen los requerimientos de negocio, sin
importar la tecnología. La idea de este artículo está de hecho dedicada
al desarrollo de tal objeto de negocio, siguiendo un ejemplo con
InterBase.
En un archivo de unidad de módulo de datos uno puede escribir métodos,
incluyendo los gestores de eventos de los componentes del módulo, así
como las rutinas globales que encapsulan las reglas de negocio. Por
ejemplo, uno puede escribir un procedimiento para realizar un cálculo
de comisión bancaria y podría llamar a tal procedimiento desde un
gestor de evento de un componente en el módulo o desde cualquier
formulario que utilice el módulo.
En un objeto de negocio simple (sin campos en la clase), uno tiene por
lo menos cuatro tareas que completar:
1. La clase Business-Class hereda de un Data-Provider
2. La consulta es parte de la clase
3. Hay que hacer un cálculo o regla de negocio
4. El objeto es independiente de la GUI, la GUI llama al objeto
1. Construimos la clase; la superclase puede ser TQuery o TDataModule:
type
TBusinessObj = class(TQuery)
private
function open_QueryFee(qryID: integer):boolean;
function calcFee(fee: double):double;
public
procedure changeFee(amount: double);
procedure changeLimit(amount: double);
end;
2. Definimos una consulta parametrizada:
function TBusinessObj.open_QueryFee(qryID: integer):boolean;
begin
Result := False;
try
SQL.Clear;
SQL.Add('SELECT * from ACCOUNT');
SQL.Add('WHERE acc_no = :pClient_acc');
Params[0].Name := 'pClient_acc';
Params[0].DataType := ftInteger;
Params[0].AsInteger := qryID;
Open;
Result := True;
finally
// basura o algo
end;
end;
3. Antes de guardar el monto, calculamos algo
procedure TBusinessObj.changeFee(amount: double);
begin
Edit;
FieldByName('FEE').AsFloat := calcFee(amount);
Post;
end;
// como una regla de negocio
function TBusinessObj.calcFee(fee: double): double;
begin
result:= (2 * fee) / BANK_FACTOR // sólo un cálculo
end;
4. Vayamos al cliente, que tiene un objeto de negocio como su miembro:
private
...
tblAccount: TBusinessObj;
end;
procedure TForm1.btnFeeClick(Sender: TObject);
begin
with tblAccount do begin
if open_QueryFee(StrToInt(edtAccount.Text)) then
changeFee(strToFloat(edtFee.text));
end;
end;
Mientras no tengamos campos en el objeto de negocio para mapear una base
de datos relacional de manera orientada a objetos, podemos hacer una
simple conversión de tipos de la instancia, sin un constructor.
procedure TForm1.FormCreate(Sender: TObject);
begin
tblAccount := TBusinessObj(Query1); // conversión de tipos
end;
Panorama:
---------
Cuando llegue la hora, puede que usted quiera mapear los atributos de
una base de datos a los campos de la clase correspondiente. Esto
significa que todas las sentencias SQL sean encapsuladas, para que así
tenga un verdadero acceso orientado a objetos, el que describiré en una
segunda parte. Veamos un ejemplo de algo destacado en programación de
bases de datos de objetos, que es similar en Boldsoft con BOLD o en
gs-soft con MetaBASE:
Person := TPerson.Create;
oAddressList := TAddressList.Create;
try
oPerson.Person_ID := 30;
oAddressList := TAddressList.DBReadAllRelatedToObject(oPerson);
for i := 0 to oAddressList.Count - 1 do
S_MBox(oPerson.LastName + ' ' + oAddressList.Adresses[i].Town);
finally
oPerson.Free;
oAddressList.Free;
end;
________________________________________________________________________
4. PREGUNTAS FRECUENTES SOBRE DELPHI 6 PERSONAL EDITION
¿Por qué la llamaron "Personal"?
================================
Porque su licencia lo limita a usarla sólo para usos no comerciales.
Cualquier propósito comercial, de negocios, gubernamental o institu-
cional de cualquier clase está expresamente prohibido. La llamaron
"personal" precisamente porque realmente es "personal".
Usted puede distribuir sus trabajos creados con la Edición Personal de
Delphi 6, pero no puede recibir ninguna compensación directa o indi-
recta. Esto significa que por ejemplo usted no puede vender licencias
de su software, cobrar por el desarrollo de una aplicación a medida,
cobrar regalías, distribuir aplicaciones "adware", etc., etc., etc.
¡"Compensación directa o indirecta" es sumamente abarcativo!!!
¿A quiénes está dirigida?
=========================
Puede sacar sus propias conclusiones. Supongo que es para hobbyistas o
para aquellos que quieren aprender algo de programación... Ciertamente
que no es para programadores que esperan obtener una remuneración por
su trabajo, ni para negocios o instituciones de ningún tipo (incluyendo
el gobierno).
¿Es gratis?
===========
Sí, es gratis, pero debe registrarse. Puede bajarla del sitio de
Borland:
http://www.borland.com/delphi/personal/index.html
¿Si es gratis, por qué Borland la vende?
========================================
La descarga es de 140 MB, demasiado para la conexión a Internet que
tienen muchas personas. Además, la versión en CD-ROM que Borland vende
por $99.95 incluye un manual impreso y soporte de instalación.
¿Es código abierto ("open source")?
===================================
No, no es open source, aunque están disponibles los fuentes de algunas
unidades (como windows.pas).
¿Tengo que distribuir mis aplicaciones bajo la GNU GPL?
=======================================================
No, eso se aplica a la Open Edition de Kylix. Con Delphi 6 Personal, si
distribuye sus aplicaciones, debe hacerlo gratuitamente, pero no está
obligado a distribuir el código fuente si no lo desea, aunque no puede
cobrar por ello si decide hacerlo.
¿Qué componentes vienen con la Edición Personal?
================================================
Delphi 6 Personal Edition viene con 85 componentes. Nada de componentes
de BD, FastNet, QReport, etc. Es muy parecida a la edición estándar de
Delphi 5 (con algunas cosas nuevas, por supuesto).
¿Hay una Edición Estándar de Delphi 6?
======================================
A partir de la versión 6, no hay una Edición Estándar de Delphi. Si está
interesado en desarrollar aplicaciones comerciales, considere adquirir
la Edición Estándar de Delphi 5.
¿Cómo instalo Delphi 6 Personal?
================================
1) Descargue Delphi 6 Personal del sitio de Borland:
http://www.borland.com/delphi/personal/index.html
En el tercer paso del proceso de descarga no se olvide de hacer clic
en el enlace "Send me a serial number and authorization key via email"
(enviarme el número de serie y la clave de autorización por email)
para recibir por email el número de serie y la clave de autorización
que se requiere poder instalar el producto.
Si usted es miembro de la Comunidad no se olvide primero de
comprobar que su nombre, dirección de email y otros datos de su
cuenta de la Comunidad sean correctos. Si usted no es miembro de la
Comunidad, compruebe que está escribiendo correctamente su nombre,
dirección de email y otros datos.
2) Corra el archivo descargado (BorlandDelphiPersonalEdition.exe). Eso
descomprimirá el instalador en una carpeta de su elección. De manera
predeterminada será en
C:\Archivos de programa\Borland Delphi Personal Installer
3) Corra el instalador (INSTALL.EXE) y haga clic en el botón "Delphi 6"
del Setup Launcher para comenzar la instalación.
4) Se le solicitará el número de serie y la clave de autorización que
le debería haber sido proporcionada por email.
5) Lea la licencia muy cuidadosamente. Si está de acuerdo con los
términos de la licencia, haga clic en el botón de radio correspon-
diente y luego haga clic en el botón "Next" (siguiente) para
continuar.
6) Proceda con el resto de la instalación de manera usual...
7) Al final puede que necesita reiniciar su sistema.
8) Después de la instalación encontrará el grupo "Borland Delphi 6" en
su menú de Inicio de Windows. Diríjase allí y corra Delphi 6.
9) Se le solicitará que se registre. Necesitará una conexión a Internet
para registrarse en línea (el proceso de registración es bastante
fácil para los miembros de la Comunidad Borland). También se puede
registrar por teléfono o con su navegador web si tiene una clave de
activación. No recibí una clave de activación así que supongo que
está disponible para quienes compren la versión en CD-ROM.
10) ¡Disfrute! :)
________________________________________________________________________
5. COMPONENTES VCL
Componente SpeedParser - Analizador Rápido de Expresiones
=========================================================
- Por Mattias Andersson <mattias@centaurix.com>
Este componente de análisis de expresiones evaluará rápidamente fórmulas
matemáticas y le permitirá definir sus propias variables.
Al evaluar expresiones matemáticas, la velocidad es toda una cuestión,
por lo que hice un intento de analizador de expresiones (expression
parser) que recompila la expresión en listas/arreglos de instrucciones y
variables.
Use la propiedad ParseString para establecer su expresión y después
simplemente llame al método Parse para realizar la evaluación. Si desea
definir su propias variables utilice los métodos AddVar y SetVar. Las
variables predefinidas son A..Z y Pi.
La aplicación demo incluida utiliza los componentes SpeedParser para
establecer los valores RGB de cada píxel en una imagen dependiendo de
expresiones que evalúan las coordinadas X e Y. El componente TImage no
es muy rápido al establecer los píxeles; si usted está buscando una
biblioteca rápida de gráficos debe darle una ojeada a Graphics32 de
Alex Denisov: http://www.g32.orgk
Mattias Andersson
Imagen PCX con soporte de paleta
================================
- Por Tommy Andersen <tommy.andersen@easyware.org>
Leí el artículo http://www.delphi3000.com/articles/article_2565.asp de Maarten
de Haan, y pensé en publicar mi propio componente de gráficos PCX con
soporte de manejo de paleta de colores, etc. Este componente no soporta
guardar imágenes PCX como el arriba mencionado, pero una pequeña combi-
nación de ambos y tendrá un gran componente! :)
Tommy Andersen
________________________________________________________________________
6. TRUCOS Y CONSEJOS
Haciendo una aplicación cliente TCP/IP - Compartiendo mi experiencia...
=======================================================================
- Por S.S.B. Magesh Puvananthiran <sesbaNOSPAM@hotmail.com>
Conectándose a un servidor TCP/IP desde un cliente Delphi
---------------------------------------------------------
Como todo desarrollador Delphi sabe, para hacer una aplicación cliente
TCP/IP en Delphi podemos utilizar el componente de TClientSocket.
Me enfrenté a un problema al tratar de conectar a un servidor TCP/IP
(otra computadora) y enviar datos a esa máquina y obtener datos de
vuelta.
En el evento OnShow del formulario, establecí las propiedades Address y
Port del componente TClientSocket con la dirección IP del servidor
TCP/IP y el número de puerto, y establecí Active en True. Después de eso
intenté enviar los datos en el mismo evento. No pude enviar los datos.
Comprobé que la propiedad Active fuera True (significando conectado).
Así que pensé que el problema podría estar en el evento OnShow del
formulario y entonces puse el mismo código (establecer la dirección IP y
el número de puerto y Active en True) en los eventos FormCreate y
OnClick, pero no pude salir de ese problema.
La cosa es que intenté conectarme con el servidor TCP/IP e intenté
enviar los datos al mismo tiempo. Esto no parece trabajar correctamente.
Después leí la ayuda de Delphi cuidadosamente y logré la solución.
La solución que encontré es:
----------------------------
Primero necesitamos establecer la dirección IP y el número de puerto del
servidor TCP/IP en el componente TClientSocket en el evento OnCreate del
formulario principal del proyecto, y establecer Active en True. Después
de ello podemos utilizar los métodos Open y Close del componente
TClientSocket para conectarnos y desconectarnos del servidor TCP/IP
respectivamente.
Si deseamos enviar datos a un servidor TCP/IP desde diferentes formu-
larios en un proyecto, podemos utilizar un módulo de datos (DataModule)
y poner el componente TClientSocket allí para utilizarlo en por todas
partes a través del proyecto, incluyendo ese módulo de datos en todos
los archivos de unidad donde deseemos utilizarlo.
Y una cosa más, en el evento ClientSocketRead necesitamos poner una
demora de tiempo mientras se leen los datos desde el servidor TCP/IP.
Este retraso podría ser de algunos milisegundos y depende del tráfico
de la red puesto que podemos no leer todos los datos enviados del
servidor TCP/IP en un momento dato, incluso si uno tiene un buffer
grande. Así que puede que necesite esperar algunos milisegundos entre
lecturas.
Utilicé el ClientType del TClientSocket como ctNonBlocking. Podemos
también utilizar ctBlocking como ClientType, pero en ese caso el
servidor TCP/IP debe ser uno multi-hilos.
Aunque puede parecer un tema sencillo, simplemente quería compartirlo
con todos nuestros amigos en Delphi.
Gracias.
Magesh.
Alineando texto en un StringGrid
================================
Para alinear texto en una cuadrícula de cadenas (StringGrid) tiene que
asignar el evento OnDrawCell donde usted tiene que calcular la posición
del texto y después dibujarlo en el lienzo. El ejemplo siguiente centra
el texto de la primera fila de un TStringGrid y alínea a la derecha el
texto de la primera columna:
procedure TForm1.StringGrid1DrawCell(Sender: TObject;
ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
CellText: string;
begin
with StringGrid1 do
if ARow = 0 then begin
CellText := Cells[ACol, ARow];
Canvas.TextRect(Rect, Rect.Left + (Rect.Right - Rect.Left
- Canvas.TextWidth(CellText) + 1) div 2, Rect.Top + 2,
CellText);
end else if ACol = 0 then begin
CellText := Cells[ACol, ARow];
Canvas.TextRect(Rect, Rect.Right - Canvas.TextWidth(CellText)
- 2, Rect.Top + 2, CellText);
end;
end;
Evitando que el usuario ejecute otras aplicaciones
==================================================
Si no quiere que los usuarios de su aplicación puedan correr otras
aplicaciones mientras la suya está corriendo, puede usar la siguiente
función para "bloquear"/"desbloquear" su sistema:
procedure ModalApp(Activate: LongBool);
var
h: cardinal;
begin
SystemParametersInfo(SPI_SCREENSAVERRUNNING,
Cardinal(Activate), @h, 0);
h := FindWindow('Shell_TrayWnd', nil);
if h <> 0 then
if Activate then
ShowWindow(h, SW_HIDE)
else
ShowWindow(h, SW_SHOWNOACTIVATE);
h := FindWindow('Progman', 'Program Manager');
if h <> 0 then
EnableWindow(h, not Activate);
end;
Asumiendo que Activate es True, la llamada a SystemParametersInfo con
SPI_SCREENSAVERRUNNING es para "engañar" al sistema operativo haciéndole
creer que el salvapantallas está corriendo. Esto tendrá el deseado
efecto colateral de inhabilitar los atajos CTRL+ALT+DEL, CTRL+ESC y
ALT+TAB. El propósito de esto es evitar que el usuario pueda forzar la
terminación de la aplicación con el Administrador de Tareas (el cierre
de la aplicación supuestamente está protegido con contraseña). Luego
encontramos el manejador (handle) de la barra de tareas para ocultarla
(o podríamos inhabilitarla) y finalmente encontramos el manejador del
escritorio para inhabilitarlo.
Llame a ModalApp pasando False como parámetro para desactivar el efecto
y regresar a la normalidad.
NOTA: Este código probablemente no funcionará en Windows NT/2000.
________________________________________________________________________
7. DELPHI EN LA RED
* Delphi Database Programming Course - By Zarko Gajic
Free online database programming course for beginner Delphi developers
focused on ADO techniques. A new chapter has been added in the last
weeks (Chapter 14 "Charting with Databases").
http://delphi.about.com/library/weekly/aa010101a.htm
* Searching for Delphi - By Zarko Gajic
Where and how to search for Delphi and Object Pascal programming
related materials on the Net.
http://delphi.about.com/library/weekly/aa121900a.htm
* Delphi Coding Standards and Conventions - By Zarko Gajic
Recommendations of standards and conventions for designing, coding,
and commenting software projects written in Delphi and Kylix.
http://delphi.about.com/cs/standards/index.htm
* Component writing, part 2 - By Peter Morris
This second part cover how to write advanced properties, how to write
custom streaming for those properties, and sub-properties
http://www.howtodothings.com/showarticle.asp?article=320
* Screen Shuffling with Delphi - By Zarko Gajic
Delphi code that divides the current desktop screen into blocks and
then swaps the blocks. It includes an option that lets you adjust the
shuffling speed, and the size of the blocks. Great intro to sliding
puzzle game or to screen saver development.
http://delphi.about.com/library/weekly/aa082801a.htm
* Listening to the Clipboard - By Zarko Gajic
Extending the clipboard's flexibility and functionality from Delphi.
Taking control over the Clipboard with custom formats. Coding Delphi
to receive clipboard change notifications.
http://delphi.about.com/library/weekly/aa110700a.htm
* Delphi Object Hierarchy - By Borland
Colorful hierarchy of all objects in all versions of Delphi 5.
http://delphi.about.com/library/doh.pdf
* Building a stand-alone Web service with Indy - By Dave Nottage
This article shows how to build a Web service using Indy and Delphi 6.
http://community.borland.com/article/0,1410,27513,00.html
* Pente: An introduction to programming strategy games - By Armando de
la Torre
This article describes the creation of a game known as Pente or Go, a
simple strategy game which has similar rules to tic-tac-toe.
http://community.borland.com/article/0,1410,27512,00.html
* Other people's windows
This article demonstrates how to subclass non-Delphi windows from
within a Delphi application.
http://community.borland.com/article/0,1410,27295,00.html
* WebSnap and Web Services hand-in-hand - By Daniel Polistchuck.
Here's a guide to combining WebSnap and Web Services to create SOAP
client web pages.
http://community.borland.com/article/0,1410,27691,00.html
* Programmers' pets - By Pintér Gábor
Every programmer has a favorite application.
http://community.borland.com/article/0,1410,26428,00.html
* Managing a birthday calendar with InterBase - By Marco Hemmes
User-defined functions are the key to remembering everyone's natal
anniversary.
http://dn.codegear.com/article/27203
* Untapped resources in Windows - By Lubomir Rosenstein
Scanning and creating shortcuts using COM and Delphi.
http://community.borland.com/article/0,1410,26174,00.html
* Generic handling for any Edit menu - By Steven C. Gudmundson
Get out of the repetitive-coding rate rat race with this flexible,
reusable code.
http://community.borland.com/article/0,1410,26842,00.html
* A Simple example of Artificial Intelligence using Delphi Array - By
Raghunath Dhungel
A Simple example of Artificial Intelligence using Delphi Array.
Computer simulates learning process of human, learning by correcting
mistakes!
http://www.delphi3000.com/articles/article_2551.asp
* How to deal with OLE DB directly, using its interfaces - By Alex
Wijoyo
An example for how to deal with OLE DB directly, using its interfaces.
http://www.delphi3000.com/articles/article_2604.asp
* Writing a simple ISAPI Filter for IIS - By Daniel Wischnewski
This article shows you the basics of creating a simple ISAPI filter
and how to use one to map sub-domains into specific folders.
http://www.delphi3000.com/articles/article_2646.asp
* How to change properties of objects just by name? - By Jürgen Sommer
How can I access properties of classes that are not implemented via
the uses-clause, just knowing their names (by string)?
http://www.delphi3000.com/articles/article_2664.asp
* How to create a DataBaseName Property? - By Geers Christophe
The following example shows how to create a component with a
DataBaseName property like the DataBaseName property of TQuery. The
purpose of this property is to list all the available databases so
that the user of the component can just select the required database.
http://www.delphi3000.com/articles/article_2692.asp
________________________________________________________________________
¡TÚ PUEDES AYUDARNOS!
Necesitamos tu ayuda para que este boletín pueda continuar y crecer. Una
forma en que puedes ayudarnos es enviando este enlace a tus amigos:
http://www.latiumsoftware.com/es/pascal/index.php
Otra forma es votándonos en alguno de estos rankings para darle más
visibilidad a nuestro sitio web y aumentar así el número de suscrip-
ciones al boletín, que esperamos en el futuro se traduzca también en un
mayor número de colaboraciones de artículos, trucos, etc.:
http://www.programmingpages.com/?r=latiumsoftwarecomenpascal
http://top100borland.com/in.php?who=20
http://www.lawebdelprogramador.com/buscar/votar.php?id=615
Por favor vota. Son sólo unos segundos para ti que REALMENTE pueden
hacer la diferencia. Necesitamos tu ayuda para poder continuar.
________________________________________________________________________
Si no has recibido el archivo con el código fuente completo de los
ejemplos que se presentan en este boletín, puedes descargarlo de la
siguiente dirección: http://www.latiumsoftware.com/es/file.php?id=p26
________________________________________________________________________
Página principal: http://www.latiumsoftware.com/es/pascal/index.php
Página del grupo: http://espanol.groups.yahoo.com/group/boletin-pascal/
Para suscribirse / apuntarse: boletin-pascal-subscribe@gruposyahoo.com
Para cancelar / removerse: boletin-pascal-unsubscribe@gruposyahoo.com
Para reportar problemas con la suscripción: eds2008 @ latiumsoftware.com
________________________________________________________________________
Este boletín se provee "TAL Y COMO ESTA", sin garantía de ninguna clase.
Su uso implica la aceptación de nuestros términos de licencia y de la
ausencia de garantía que puedes leer en nuestro sitio web. Allí también
encontrarás una nota sobre marcas registradas. Te animamos a que redis-
tribuyas este boletín, siempre y cuando lo hagas en forma completa
(incluyendo la información de copyright), sin modificaciones y de manera
gratuita. Los artículos son copyright de sus respectivos autores y se
reproducen aquí con el permiso de los mismos.
________________________________________________________________________
Latium Software http://www.latiumsoftware.com/es/index.php
Copyright (c) 2001 por Ernesto De Spirito. Todos los derechos reservados
________________________________________________________________________
|