Boletín Pascal #22 - 18-MAY-2001
INDICE
1. UNAS PALABRAS DEL EDITOR
2. DELPHI 6
3. VALIDANDO DIRECCIONES DE EMAIL EN DELPHI
4. VIEJOS TIEMPOS (II) - Opinión - Por H.R Quiroga
- Un programador de verdad
- Volviendo a principio de los 80
- La Guerra Santa
- Basic y Java
- En la actualidad
- A donde vamos
5. FUNCIONES MISCELANEAS DE MANEJO DE CADENAS
- Contando ocurrencias en una cadena
- Dividiendo una cadena en un arreglo
- Dividiendo una cadena en una lista de cadenas
- Convirtiendo TimeStamps de MySql
6. GREATIS PRINT SUITE
- ¿Qué es Greatis Print Suite?
- Componentes
- Descarga
- Licencia
- Más información
7. ¿COPIAR, HEREDAR O USAR?
8. DELPHI EN LA RED
________________________________________________________________________
1. UNAS PALABRAS DEL EDITOR
Y LA LICENCIA ES PARA...
Roberto Martinez Olvera, de 31 años, Ejecutivo de Sistemas de IEQSA,
Querétaro (México), ha resultado ser el ganador del Sorteo de Help &
Manual, por tener el número 059 (correspondiente al segundo premio de
la Lotería de Córdoba, dado que ningún participante tenía el número
347 correspondiente al primer premio). ¡Felicitaciones!
ERRATA
La rutina presentada en el artículo "Obteniendo el número de serie del
BIOS" en el boletín pasado no funciona en Windows NT/2000 causando una
AV. Puede ver los comentarios (en inglés) en
http://www.delphi3000.com/articles/article_2194.asp#Comments
Atentamente,
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 6
Si -como yo- usted pensaba que Delphi 6 sólo iba a introducir algunas
mejoras sobre Delphi 5 y que la portabilidad con Kylix iba a ser la
estrella en la nueva versión de Delphi, estaba totalmente equivocado...
Mientras el Visual Studio .NET de Microsoft todavía está en su primer
beta, Borland anunció la disponibilidad de Delphi para el 8 de Junio y
ya está tomando preórdenes. De esta manera Delphi 6 será la primer
herramienta RAD para Windows con soporte completo para Web Services
(Servicios Web), el nuevo estándar de la industria, habilitando inte-
gración inmediata y progresiva con plataformas basadas en Web Services
de otros fabricantes como por ejemplo .Net y BizTalk de Microsoft, y ONE
de Sun Microsystems.
Más información:
* Borland unveils industry's first RAD Web Services development platform
http://www.borland.com/about/press/2001/del6released.html
* Borland enters Web services fray
http://www.infoworld.com/articles/hn/xml/01/05/07/010507hnborland.xml
* Borland aims to make Web services a "Snap"
http://www.zdnet.com/eweek/stories/general/0,11011,2712635,00.html
* Delphi gets corporate
http://www.comp-buyer.co.uk/index71/newnews/newsarticle.php3?id=2124
* Screenshots and articles on Delphi 6 in the Delphi community
http://community.borland.com/delphi/0,1419,1,00.html
* What's new in Delphi 6
http://www.borland.com/delphi/del6/whatsnew.html
* Delphi 6 feature matrix
http://www.borland.com/delphi/del6/featurematrix/
* Delphi 6 system requirements
http://www.borland.com/delphi/del6/sysreq.html
* Delphi 6 editions and prices
http://shop.borland.com/Category/0,1257,3-15-983,00.html
________________________________________________________________________
3. VALIDANDO DIRECCIONES DE EMAIL EN DELPHI
Hoy en día muy común que nuestros programas guarden direcciones de email
en bases de datos como parte de los datos de empleados, clientes,
proveedores, etc. Al solicitar una dirección de email al usuario, ¿cómo
sabemos si el valor ingresado es formalmente correcto? En este artículo
le mostraré como validar direcciones de email usando una variación de la
RFC #822.
La RFC #822 regula el "ESTÁNDAR PARA EL FORMATO DE LOS MENSAJES DE TEXTO
DE ARPA INTERNET". Puede encontrarla en:
http://www.isi.edu/in-notes/rfc822.txt (en inglés)
Según esta normativa, las siguientes son direcciones de email válidas:
Juan Perez jperez@servidor.com
Juan Perez <jperez@servidor.com>
"Juan Perez" jperez@servidor.com
"Juan Perez" <jperez@servidor.com>
El propósito de mi código no es validar esas cosas, sino estrictamente
la dirección que se necesita para llegar a un destinatario (como
"jperez@servidor.com"), que en la especificación se refiere como un
"addr-spec", que tiene la siguiente forma:
parte-local@dominio
parte-local = una "palabra" o más, separadas por puntos
dominio = un "sub-dominio" o más, separados por puntos
Una "palabra" puede ser un "átomo" o una "cadena-entrecomillada":
átomo = uno o más caracteres en el rango #33..#126 con excepción de
los siguientes: ()<>@,;:\/".[]
cadena-entrecomillada = Un texto encerrado en comillas dobles que
puede contener cero o más caracteres (#0..#127) excepto '"' y #13.
La barra invertida ('\') "literaliza" el siguiente caracter.
Un "sub-dominio" puede ser un "ref-de-dominio" (un "atom") o un
"literal-de-dominio":
literal-de-dominio = Un texto encerrado entre corchetes que puede
contener cero o más caracteres (#0..#127) excepto '[', ']' y #13.
La barra invertida ('\') "literaliza" el siguiente caracter.
Según la RFC 822, los caracteres extendidos (#128..#255) no pueden ser
parte de una dirección de email, pero no obstante ello muchos servidores
del correo los aceptan y la gente los usa, así que voy a tomarlos en
cuenta.
La RFC 822 es muy abierta acerca de los nombres de dominio. Para una
dirección de email real de Internet quizás deberíamos restringir la
parte del dominio. Puede leer más sobre nombres del dominio en la RFC
#1034 y RFC #1035 que puede encontrar aquí:
http://www.ietf.org/rfc/rfc1034.txt
http://www.ietf.org/rfc/rfc1035.txt
Para la RFC 1034 y la RFC 1035, un nombre de dominio se forma por "sub-
dominios" separados por puntos, y cada subdominio comienza con una letra
('a..'z', 'A..'Z') seguida por cero o más letras, dígitos y guiones,
pero no puede terminar con un guión. Vamos a considerar además que un
dominio válido debe tener por lo menos dos "sub-dominios" (como
"host.com").
Ahora que tenemos las reglas claras, vamos al trabajo. El algoritmo para
la función se asemeja a una máquina de transición de estados. Los
caracteres de la cadena se procesan en un bucle, y por cada caracter
primero determinamos en qué estado se encuentra la máquina (con un
"case..of") y luego procesamos el carácter de acuerdo con eso, para
determinar si la máquina debe continuar en ese estado, pasar a un estado
diferente o producir un error (cortando el bucle con "break"). Este
clase de algoritmos se tratan extensamente en libros de algoritmos de
programación, así vayamos directo al código:
function ValidEmail(email: string): boolean;
// Devuelve True si la dirección de email es válida
// Autor: Ernesto De Spirito <eds2008 @ latiumsoftware.com>
const
// Caracteres válidos en un "átomo"
atom_chars = [#33..#255] - ['(', ')', '<', '>', '@', ',', ';', ':',
'\', '/', '"', '.', '[', ']', #127];
// Caracteres válidos en una "cadena-entrecomillada"
quoted_string_chars = [#0..#255] - ['"', #13, '\'];
// Caracteres válidos en un subdominio
letters = ['A'..'Z', 'a'..'z'];
letters_digits = ['0'..'9', 'A'..'Z', 'a'..'z'];
subdomain_chars = ['-', '0'..'9', 'A'..'Z', 'a'..'z'];
type
States = (STATE_BEGIN, STATE_ATOM, STATE_QTEXT, STATE_QCHAR,
STATE_QUOTE, STATE_LOCAL_PERIOD, STATE_EXPECTING_SUBDOMAIN,
STATE_SUBDOMAIN, STATE_HYPHEN);
var
State: States;
i, n, subdomains: integer;
c: char;
begin
State := STATE_BEGIN;
n := Length(email);
i := 1;
subdomains := 1;
while (i <= n) do begin
c := email[i];
case State of
STATE_BEGIN:
if c in atom_chars then
State := STATE_ATOM
else if c = '"' then
State := STATE_QTEXT
else
break;
STATE_ATOM:
if c = '@' then
State := STATE_EXPECTING_SUBDOMAIN
else if c = '.' then
State := STATE_LOCAL_PERIOD
else if not (c in atom_chars) then
break;
STATE_QTEXT:
if c = '\' then
State := STATE_QCHAR
else if c = '"' then
State := STATE_QUOTE
else if not (c in quoted_string_chars) then
break;
STATE_QCHAR:
State := STATE_QTEXT;
STATE_QUOTE:
if c = '@' then
State := STATE_EXPECTING_SUBDOMAIN
else if c = '.' then
State := STATE_LOCAL_PERIOD
else
break;
STATE_LOCAL_PERIOD:
if c in atom_chars then
State := STATE_ATOM
else if c = '"' then
State := STATE_QTEXT
else
break;
STATE_EXPECTING_SUBDOMAIN:
if c in letters then
State := STATE_SUBDOMAIN
else
break;
STATE_SUBDOMAIN:
if c = '.' then begin
inc(subdomains);
State := STATE_EXPECTING_SUBDOMAIN
end else if c = '-' then
State := STATE_HYPHEN
else if not (c in letters_digits) then
break;
STATE_HYPHEN:
if c in letters_digits then
State := STATE_SUBDOMAIN
else if c <> '-' then
break;
end;
inc(i);
end;
if i <= n then
Result := False
else
Result := (State = STATE_SUBDOMAIN) and (subdomains >= 2);
end;
Cualquier colaboración para mejorar esta función es bienvenida.
________________________________________________________________________
4. VIEJOS TIEMPOS (I) - Opinión - Por H.R Quiroga
Un programador de verdad
------------------------
Muchos quizás hayan leído la frase "Real Programmers Don't Use Pascal"
("Los verdaderos programadores no usan Pascal"). Esta frase pertenece a
un artículo de 1983 publicado en "Datamation" por Ed Post. Las cosas han
cambiado al grado que muchos de los utilitarios de "PCMagazine" están
hechos en Delphi, y si esos programadores no son de "verdad", no queda
mucho para mí. No pienso que mi conocimiento de C, Assembler, Fortran,
Cobol, Clipper y demás lenguajes me hagan más "real".
Volviendo a principio de los 80
-------------------------------
Cuando apareció Turbo Pascal de Borland, Microsoft vendía un compilador
de Pascal (tengo recuerdos nebulosos de ello, así que disculpen si no
soy exacto). Se requerían tres disquetes, compilación y enlace en varios
pasos y varios cientos de dólares por licencia, además de algún editor
como Wordstar. Por otro lado "Turbo Pascal" necesitaba 32K, tenía un
editor integrado, generaba ejecutables de unos 30K que eran mucho
menores de los de la competencia y llegó a costar menos de 100 dólares.
Entenderán por qué Microsoft eventualmente se retiró de esa competencia
(es posible que hayan eliminado cualquier registro histórico de este
fracaso como el protagonista de la novela de Orwell en la novela 1984).
Uno probaba Turbo Pascal pensando en lo ridículo del nombre... Pronto
dejaba de sonar ridículo.
En el camino hubo algunas pérdidas importantes. Paz a los restos de
"Topspeed Modula-2".
La Guerra Santa
---------------
En computación las "Guerras Santas" se basan en posiciones no técnicas
(casi religiosas) llevadas por medio de silogismos a posiciones
técnicas. Son divertidísimas o al menos ingeniosas. Siempre ha habido
guerras de C vs. alguna cosa. Obviamente "C" vs. "Pascal". La guerra no
destrozó mucho y ambos lenguajes sobreviven hoy en día. El compilador de
Object Pascal es en extremo lejano a Pascal como quizás el de C++ a C.
Paradójicamente este artículo se parece mucho a la artillería de una
guerra santa ;-> y dado el foro donde expongo esto, es casi convencer a
los convencidos. En cualquier caso, los defectos señalados a cada
lenguaje durante las guerras fueron muy ciertos en su mayoría. Muchos
cambios en estos lenguajes son sólo para cubrir esas terribles
debilidades.
Basic y Java
------------
Siempre ha existido algo muy molesto en la persistencia de Basic, y no
sólo es su origen; es también su pobre evolución. Basic sobrevive porque
Microsoft lo mantiene; cosa que podríamos afirmar también de Pascal con
respecto a Borland (creo que en algún momento ha sido al contrario).
Quizás de esto se salven C, derivados y Java. Microsoft ha intentado en
vano echarnos a perder Java. Borland, en un camino más discreto, aportó
cosas importantes a su especificación (léase JavaBeans) sin intentar
apropiárselo, y de esta manera discreta mantienen uno de las mejores
herramientas de desarrollo Java. Será interesante ver el futuro de Java
y Borland.
Basic, con lo terrible que es, aún existe derivado en Visual Basic.
Detesto enfrentarme a programadores de Visual Basic que insisten en que
debo usarlo, sin importarles que yo de hecho lo he utilizado y
abandonado. Actualmente pienso dedicarle algo de esfuerzo a Java. Me
parece que esto aportará algo útil o por lo menos me dará la oportunidad
de rechazarlo con propiedad.
En la actualidad
----------------
Ya sabemos que Pascal tiene presencia en la actualidad y de manera
significativa aplicado a través de Delphi. Lo interesante es ver en
dónde se aplica y si podemos reconocer por esto su madurez. Sabemos que
la NASA lo usa. Sabemos también que hay algunas aplicaciones comerciales
hechas con Delphi. Lo que me gustaría ver es una Suite Completa de
oficina hecha con Delphi; sin embargo, sé que ese es un mercado muy
difícil, así que por lo pronto sólo es un sueño. Debo añadir que este
sueño tiene un ambiente Linux.
A dónde vamos
-------------
Sí, primera persona en plural. Marco Cantú dijo "Dephi no es sólo un
producto. Es una comunidad". Esta comunidad parece impulsada cada vez
más por medio de la Internet y por lo visto cada vez crece más.
Me agrada pertenecer a la Comunidad de Delphi y creo que somos muchos y
entusiastas, y por ello debemos hacernos notar. No importa que se vendan
más copias de Visual alguna cosa si la calidad de nuestro trabajo es
superior y llena de mucho más gusto.
Es inevitable mencionar Kylix. Cualquier vaticinio aún es un poco
aventurado. Espero que incluso eventualmente escuchemos de Delphi para
Mac o algo así. A diferencia de la Mac creo que Linux no va disminuir su
ímpetu.
-------------
Para recordar la historia recomiendo un vistazo a (muchos datos precisos
aquí señalados provienen de esta fuente):
"THE JARGON FILE, VERSION 2.9.12", conocido como
"The Hacker's Dictionary".
Otros datos son tomados de artículos de Marco Cantú (www.marcocantu.com)
------------------------------------
Copyright (c) 2001 H.R Quiroga
________________________________________________________________________
5. BUSCANDO TEXTO EN UN CAMPO MEMO
Si necesita buscar texto en un campo memo, puede hacerlo recorriendo el
dataset registro por registro para ver si el texto buscado se encuentra
en el campo memo o no:
procedure TForm1.btnFindClick(Sender: TObject);
var
SearchStr: string;
begin
SearchStr := UpperCase(Edit1.Text);
Table1.DisableControls;
if Sender = btnFindFirst then
Table1.First // Botón Find First
else
if not Table1.Eof then Table1.Next; // Botón Find Next
while not Table1.Eof and (AnsiPos(SearchStr,
UpperCase(Table1Notes.AsString)) = 0) do
Table1.Next;
Table1.EnableControls;
if Table1.Eof then ShowMessage('No encontrado')
end;
El código fuente completo de este ejemplo puede encontrarlo en el
archivo adjunto a este boletín.
________________________________________________________________________
6. GREATIS PRINT SUITE
¿Qué es Greatis Print Suite?
----------------------------
Greatis Print Suite es un extremadamente conveniente juego de compo-
nentes que permiten incorporar características avanzadas de impresión y
previsualización a las aplicaciones hechas con Delphi y C++ Builder.
Componentes
-----------
La suite contiene:
* TPrintJob: Principal componente no visual de la suite que provee fácil
impresión multipágina
* TPreview: Control que provee fácil previsualización de impresión
* TPreviewWindow: Ventana de previsualización lista para usar
* TPreviewToolbar: Barra de herramientas lista para usar que provee
control de previsualización
* TPreviewStatusBar: Barra de estado lista para usar que permite mostrar
parámetros de previsualización
* TPreviewComboBox: Cuadro combinado que muestra y provee control de la
escala de previsualización
* TPreviewLabel: Etiqueta para mostrar parámetros de previsualización
Greatis Print Suite Pro contiene adicionalmente el paquete Print Jobs
- un juego de componentes listos para usar para imprimir cuadrículas,
bases de datos y tablas, con varias clases abstractas para crear
trabajos de impresión a la medida.
* TSimpleGridPrintJob: Para imprimir fácilmente cualquier cuadrícula
gráfica
* TSimpleTextGridPrintJob: Para imprimir fácilmente cualquier cuadrícula
de texto
* TDBGridPrintJob: Para imprimir fácilmente cualquier cuadrícula de
datos
* TStringGridPrintJob: Para imprimir fácilmente el contenido de un
TStringGrid
* TListViewPrintJob: Para imprimir fácilmente el contenido de un
TListView
* TStringsPrintJob: Para imprimir fácilmente el contenido de archivos de
texto y TStrings
* TMultiPrintJob: Componente para integrar otros trabajos de impresión
* TDraftPrintJob: Componente para impresión borrador (tipo diapos)
Olvídese de BeginDoc, EndDoc, NewPage y otros procedimientos de
impresión de bajo nivel. Simplemente dibuje su trabajo de impresión y
deje que Print Suite se encargue del resto.
Descarga
--------
Un EXE-demo compilado, documentación imprimible en formato PDF y las
versiones de prueba de todos los componentes Print Suite Pro se incluyen
en el kit demostrativo, que puede descargar de la siguiente dirección:
http://www.greatis.com/printsuitedemo.zip (~735K)
Si lo desea puede solicitar una copia de evaluación.
Licencia
--------
Print Suite cuesta US$ 29.95-39.95 para una licencia de un sólo usuario.
Más información
---------------
Vea más información en la página web de Print Suite:
http://www.greatis.com/delphicb/printsuite/
Para más información, contacte Greatis Software <b-team@greatis.com>
________________________________________________________________________
7. FUNCIONES MISCELANEAS DE MANEJO DE CADENAS - Por Ernesto De Spirito
Por si alguien las encuentra útiles, aquí van algunas funciones de
manejo de cadenas que me han pedido en mi "Delphi Help Desk".
Contando ocurrencias en una cadena
==================================
Las siguientes funciones devuelven la cantidad de ocurrencias de un
caracter o una subcadena dentro de una cadena:
interface
function Occurs(const str: string; c: char): integer; overload;
function Occurs(const str: string; const substr: string): integer;
overload;
function AnsiOccurs(const str: string; const substr: string): integer;
implementation
uses sysutils;
function Occurs(const str: string; c: char): integer;
// Devuelve la cantidad de veces que un caracter está en una cadena
var
p: PChar;
begin
Result := 0;
p := PChar(Pointer(str));
while p <> nil do begin
p := StrScan(p, c);
if p <> nil then begin
inc(Result);
inc(p);
end;
end;
end;
function Occurs(const str: string; const substr: string): integer;
// Devuelve la cantidad de veces que una subcadena está en una cadena
var
p, q: PChar;
n: integer;
begin
Result := 0;
n := Length(substr);
if n = 0 then exit;
q := PChar(Pointer(substr));
p := PChar(Pointer(str));
while p <> nil do begin
p := StrPos(p, q);
if p <> nil then begin
inc(Result);
inc(p, n);
end;
end;
end;
function AnsiOccurs(const str: string; const substr: string): integer;
// Devuelve la cantidad de veces que una subcadena está en una cadena
// Versión ANSI
var
p, q: PChar;
n: integer;
begin
Result := 0;
n := Length(substr);
if n = 0 then exit;
q := PChar(Pointer(substr));
p := PChar(Pointer(str));
while p <> nil do begin
p := AnsiStrPos(p, q);
if p <> nil then begin
inc(Result);
inc(p, n);
end;
end;
end;
Dividiendo una cadena en un arreglo
===================================
Las siguientes funciones dividen una cadena en partes separadas por una
subcadena y devuelven las partes en un arreglo dinámico de cadenas:
interface
type
TStringArray = array of string;
function Split(const str: string;
const separator: string = ','): TStringArray;
function AnsiSplit(const str: string;
const separator: string = ','): TStringArray;
implementation
uses sysutils;
function Split(const str: string;
const separator: string): TStringArray;
// Devuelve un arreglo con las partes de "str" separadas por
// "separator"
var
i, n: integer;
p, q, s: PChar;
begin
SetLength(Result, Occurs(str, separator)+1);
p := PChar(str);
s := PChar(separator);
n := Length(separator);
i := 0;
repeat
q := StrPos(p, s);
if q = nil then q := StrScan(p, #0);
SetString(Result[i], p, q - p);
p := q + n;
inc(i);
until q^ = #0;
end;
function AnsiSplit(const str: string;
const separator: string): TStringArray;
// Devuelve un arreglo con las partes de "str" separadas por
// "separator"
// Versión ANSI
var
i, n: integer;
p, q, s: PChar;
begin
SetLength(Result, AnsiOccurs(str, separator)+1);
p := PChar(str);
s := PChar(separator);
n := Length(separator);
i := 0;
repeat
q := AnsiStrPos(p, s);
if q = nil then q := AnsiStrScan(p, #0);
SetString(Result[i], p, q - p);
p := q + n;
inc(i);
until q^ = #0;
end;
Ejemplo:
procedure TForm1.Button1Click(Sender: TObject);
var
a: TStringArray;
i: integer;
begin
a := Split('parte1,parte2,parte3');
for i := 0 to Length(a) - 1 do begin // Mostrará tres diálogos
ShowMessage(a[i]); // 'parte1', 'parte2', 'parte3'
end;
end;
Dividiendo una cadena en una lista de cadenas
=============================================
Las siguientes funciones dividen una cadena en partes separadas por una
subcadena y devuelven las partes en una lista de cadenas que puede ser
pasada como tercer parámetro o ser creada por la función (y en tal caso
deberá ser liberada por el llamador):
interface
uses classes;
function SplitStrings(const str: string;
const separator: string = ',';
Strings: TStrings = nil): TStrings;
function AnsiSplitStrings(const str: string;
const separator: string = ',';
Strings: TStrings = nil): TStrings;
implementation
uses sysutils;
function SplitStrings(const str: string; const separator: string;
Strings: TStrings): TStrings;
// Llena una lista de cadenas con las partes de "str" separadas por
// "separator". Si se pasa Nil en vez de una lista de cadenas, la
// función crea un objecto TStringList que debe ser liberado por el
// llamador
var
n: integer;
p, q, s: PChar;
item: string;
begin
if Strings = nil then
Result := TStringList.Create
else
Result := Strings;
try
p := PChar(str);
s := PChar(separator);
n := Length(separator);
repeat
q := StrPos(p, s);
if q = nil then q := StrScan(p, #0);
SetString(item, p, q - p);
Result.Add(item);
p := q + n;
until q^ = #0;
except
item := '';
if Strings = nil then Result.Free;
raise;
end;
end;
function AnsiSplitStrings(const str: string; const separator: string;
Strings: TStrings): TStrings;
// Llena una lista de cadenas con las partes de "str" separadas por
// "separator". Si se pasa Nil en vez de una lista de cadenas, la
// función crea un objecto TStringList que debe ser liberado por el
// llamador
// Versión ANSI
var
n: integer;
p, q, s: PChar;
item: string;
begin
if Strings = nil then
Result := TStringList.Create
else
Result := Strings;
try
p := PChar(str);
s := PChar(separator);
n := Length(separator);
repeat
q := AnsiStrPos(p, s);
if q = nil then q := AnsiStrScan(p, #0);
SetString(item, p, q - p);
Result.Add(item);
p := q + n;
until q^ = #0;
except
item := '';
if Strings = nil then Result.Free;
raise;
end;
end;
Ejemplos:
procedure TForm1.Button1Click(Sender: TObject);
begin
SplitStrings(Edit1.Text, ', ', ListBox1.Items);
end;
procedure TForm1.Button2Click(Sender: TObject);
var
Parts: TStrings;
begin
Parts := nil;
try
Parts := SplitStrings(Edit1.Text, ', ');
ShowMessage('La primera parte es "' + Parts[0] + '"');
finally
Parts.Free;
end;
end;
Convirtiendo TimeStamps de MySql
================================
Las siguientes funciones convierten timestamps completas de MySql
(cadenas en formato 'YYYYMMDDHHMMSS') a un Variant tipo TDateTime y
viceversa.
uses sysutils;
function MySqlTimeStampToDateTime(const TimeStamp: string): variant;
// Convierte un TimeStamp de MySql a un TDateTime de Delphi
begin
if TimeStamp = '' then
Result := Null
else
Result := EncodeDate(StrToInt(Copy(TimeStamp, 1, 4)),
StrToInt(Copy(TimeStamp, 5, 2)),
StrToInt(Copy(TimeStamp, 7, 2))) +
EncodeTime(StrToInt(Copy(TimeStamp, 9, 2)),
StrToInt(Copy(TimeStamp, 11, 2)),
StrToInt(Copy(TimeStamp, 13, 2)), 0);
end;
function DateTimeToMySqlTimeStamp(DateTime: variant): string;
// Convierte un TDateTime de Delphi a un TimeStamp de MySql
begin
if VarType(DateTime) in [varNull, varEmpty] then
Result := ''
else
Result := FormatDateTime('yyyymmddhhnnss', DateTime);
end;
Ejemplo:
procedure TForm1.Button1Click(Sender: TObject);
var
timestamp: string;
begin
timestamp := DateTimeToMySqlTimeStamp(Now);
ShowMessage(timestamp + #13#13 +
DateTimeToStr(MySqlTimeStampToDateTime(timestamp)));
end;
________________________________________________________________________
8. ¿COPIAR, HEREDAR O USAR?
La reutilización de código nos ahorra tiempo y esfuerzo, aumentando
nuestra productividad. La programación orientada a objetos tiene que
ver con eso, y en el caso de Delphi se pueden reutilizar hasta los
formularios e incluso proyectos enteros. Por ejemplo si tenemos un
formulario con una tabla, un dbgrid, un navegador y varios botones para
funciones varias, podemos guardarlo como un modelo en el Repositorio de
Objetos para reutilizarlo en varias partes de nuestra aplicación o en
otras aplicaciones. Lo mismo para un formulario estándar tipo "Guardar,
No guardar, Cancelar". Para agregar un formulario al repositorio le
hacemos clic con el botón derecho del ratón y elegimos "Add to
Repository...". Para guardar un proyecto en el repositorio elegimos
"Add to Repository..." en el menú Project.
Para usar un formulario del Repositorio en nuestra aplicación, en el
menú File elegimos New y en el diálogo New Items hacemos clic en la
solapa Forms para ver los formularios disponibles en el Repositorio.
Seleccionamos el formulario deseado, la forma de uso (Copy, Inherit, o
Use) y hacemos clic el botón OK. Las diferencias entre estas tres
formas de uso se describen brevemente a continuación:
COPIAR (Copy): Crea un formulario que es copia del formulario que está
en el repositorio. Los cambios que se hagan a la copia no afectarán al
formulario en el repositorio (y obviamente tampoco a los proyectos
que lo usen), así como los cambios hechos en el formulario del
repositorio no afectarán los formularios previamente copiados de él.
El nivel posible de adaptación es total. Esta opción se usa cuando el
formulario del repositorio es apenas una base para trabajar, con un muy
bajo nivel de estandarización.
HEREDAR (Inherit): Crea un formulario que hereda del formulario en el
repositorio. Los cambios que se hagan a este formulario derivado
(heredado) no afectarán al formulario en el repositorio, pero sí a la
inversa. Es la forma más poderosa para usar un formulario en el
repositorio. Esta opción se usa cuando el formulario del repositorio
está bastante estandarizado pero se desea permitir algo de adaptación.
USAR (Use): Agrega el formulario del repositorio al proyecto, pero no
es una copia, sino que ES el formulario del repositorio y cualquier
modificación que se le haga se aplicará a otros proyectos que lo Usen o
lo Hereden. Esta opción se usa cuando el formulario del repositorio es
un estándar y está definido en sí mismo (no requiere de adaptaciones
particulares para cada caso/aplicación).
________________________________________________________________________
9. 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
two weeks (Chapter 8 "Data filtering").
http://delphi.about.com/compute/delphi/library/weekly/aa010101a.htm
* Learning Assembler with Delphi - by Ian Hodger
http://www.delphi3000.com/articles/article_2245.asp
* Starting an application as an icon in the system tray - by De Spirito
http://www.delphi3000.com/articles/article_1606.asp
* QuickReports Manuals and Tutorials - by QuSoft
http://www.quickreport.co.uk/QR5_Downloaddoc.html
________________________________________________________________________
¡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=p22
________________________________________________________________________
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
________________________________________________________________________
|