Вы находитесь на странице: 1из 305

Entender los métodos de la clase Delphi

• by Zarko Gajic

En Delphi, un método es un procedimiento o función que realiza una operación en


un objeto. Un método de clase es un método que opera en una referencia de
clase en lugar de una referencia de objeto.

Si lee entre líneas, encontrará que los métodos de clase son accesibles incluso
cuando no haya creado una instancia de la clase (el objeto).

Métodos de Clase vs. Métodos de Objeto

Cada vez que crea dinámicamente un componente Delphi , utiliza un método de


clase: el Constructor .

Create constructor es un método de clase, a diferencia de prácticamente todos los


demás métodos que encontrará en la programación Delphi, que son métodos de
objeto. Un método de clase es un método de la clase, y lo suficientemente
apropiado, un método de objeto es un método que puede llamar una instancia de
la clase. Esto se ilustra mejor con un ejemplo, con clases y objetos resaltados en
rojo para mayor claridad:

myCheckbox: = TCheckbox.Create (nil);

Aquí, la llamada a Crear está precedida por el nombre de la clase y un punto


("TCheckbox."). Es un método de la clase, comúnmente conocido como un
constructor. Este es el mecanismo por el cual se crean instancias de una clase. El
resultado es una instancia de la clase TCheckbox. Estas instancias se llaman
objetos. Contraste la línea de código anterior con lo siguiente:

myCheckbox.Repaint;

Aquí, se llama al método Repaint del objeto TCheckbox (heredado de


TWinControl). La llamada a Repaint está precedida por la variable de objeto y un
punto ("myCheckbox.").

Los métodos de clase se pueden invocar sin una instancia de la clase (p. Ej.,
"TCheckbox.Create"). Los métodos de clase también se pueden invocar
directamente desde un objeto (p. Ej., "MyCheckbox.ClassName"). Sin embargo,
los métodos de objeto solo pueden invocarse mediante una instancia de una clase
(por ejemplo, "myCheckbox.Repaint").

Detrás de escena, el constructor Create está asignando memoria para el objeto (y


realizando cualquier inicialización adicional como lo especifica TCheckbox o sus
antepasados).
Experimentando con sus propios métodos de clase

Piense en AboutBox (un formulario personalizado "Acerca de esta aplicación"). El


siguiente código usa algo como:

~~~~~~~~~~~~~~~~~~~~~~~~~
procedimiento TfrMain.mnuInfoClick (Sender: TObject);
empezar
AboutBox: = TAboutBox.Create (nil);
tratar
AboutBox.ShowModal;
finalmente
AboutBox.Release;
fin;
fin;
~~~~~~~~~~~~~~~~~~~~~~~~~

Esto, por supuesto, es una muy buena forma de hacer el trabajo, pero solo para
hacer que el código sea más fácil de leer (y administrar), sería mucho más
eficiente cambiarlo a:

~~~~~~~~~~~~~~~~~~~~~~~~~
procedimiento TfrMain.mnuInfoClick (Sender: TObject);
empezar
TAboutBox.ShowYourself;
fin;
~~~~~~~~~~~~~~~~~~~~~~~~~

La línea anterior llama al método de clase "ShowYourself" de la clase TAboutBox.


El "ShowYourself" debe estar marcado con la palabra clave " class ":

~~~~~~~~~~~~~~~~~~~~~~~~~
procedimiento de clase TAboutBox.ShowYourself;
empezar
AboutBox: = TAboutBox.Create (nil);
tratar
AboutBox.ShowModal;
finalmente
AboutBox.Release;
fin;
fin;
~~~~~~~~~~~~~~~~~~~~~~~~~

Cosas a tener en cuenta


▪ La definición de un método de clase debe incluir la clase de palabra reservada
antes del procedimiento o la palabra clave de función que inicia la definición.
▪ El formulario AboutBox no se crea automáticamente (Project-Options).
▪ Coloque la unidad AboutBox en la cláusula uses de la forma principal.

▪ No olvide declarar el procedimiento en la parte de interfaz (pública) de la


unidad AboutBox.

Manejo de errores y excepciones en


aplicaciones Delphi
• by Zarko Gajic
• La línea de código más libre de errores es la que no tiene que escribir!

• Desafortunadamente, la construcción de aplicaciones incluye codificación.


Independientemente de cuán cuidadosamente escriba / depure su
programa, será imposible imaginar cada situación que pueda salir mal. El
usuario inexperto podría, por ejemplo, intentar abrir un archivo inexistente o
ingresar un valor incorrecto en un campo de datos.
Los usuarios cometen errores y debemos estar preparados para manejar /
prevenir estos errores donde sea y cuando sea posible.

• Errores, Excepciones?
• Una excepción generalmente es una condición de error u otro evento que
interrumpe el flujo normal de ejecución en una aplicación. Cuando se
produce un error al procesar una línea de código, Delphi crea (aumenta) un
descendiente de objeto de TObject llamado objeto de excepción.

• Bloques guardados
• Una aplicación responde a una excepción ejecutando un código de
terminación, manejando la excepción o ambas. La forma de habilitar la
captura de error / excepción dentro de un código dado, la excepción debe
ocurrir dentro de un bloque de instrucciones oculto. El código general se ve
así:

• > prueba {bloque de código guardado} excepto en do begin {exception block-


handleles SomeException} end; fin;

• Una instrucción try / except ejecuta las instrucciones en el bloque de


código protegido. Si las instrucciones se ejecutan sin que se genere
ninguna excepción, se ignora el bloque de excepción y el control pasa a la
instrucción que sigue a la palabra clave final.

• Ejemplo:
• > ... Cero: = 0; try dummy: = 10 / Zero; excepto en EZeroDivide do MessageDlg ('No
se puede dividir por cero!', mtError, [mbOK], 0); fin; ...

• Protección de recursos
• Cuando una sección de código adquiere un recurso, a menudo es
necesario garantizar que el recurso se libera nuevamente (o puede tener
una fuga de memoria ), independientemente de si el código se completa
normalmente o si se interrumpe con una excepción.

• En este caso, la sintaxis utiliza finalmente la palabra clave y se ve así:

• > {algún código para asignar recursos} intente {bloque de código guardado}
finalmente {bloque de terminación - código para liberar recursos} final;

• Ejemplo:

• > ... AboutBox: = TAboutBox.Create (nil); prueba AboutBox.ShowModal; finalmente


AboutBox.Release; fin; ...

• Application.OnException
• Si su aplicación no maneja el error que causó la excepción, Delphi usará su
manejador de excepción predeterminado: aparecerá un cuadro de mensaje.
Puede considerar escribir código en el evento OnException para el objeto
TApplication, para atrapar errores en el nivel de la aplicación.

• Break On Exceptions
• Al crear un programa con manejo de excepciones, es posible que no desee
que Delphi incumpla las Excepciones. Esta es una gran característica si
desea que Delphi muestre dónde se ha producido una excepción; sin
embargo, puede ser molesto cuando prueba su propio manejo de
excepciones.

• Pocas palabras finales


• La idea de este artículo es darle una rápida mirada a las excepciones. Para
una discusión más detallada sobre el manejo de excepciones, considere
el Manejo de excepciones en el manejo de excepciones de Delphi , usando
una herramienta como Delphi Crash / Exception Handling con Bug
Reporting y algunos de los siguientes artículos relacionados:

Trabajando con imágenes GIF en Delphi


• by Zarko Gajic

¿Necesita mostrar una imagen GIF animada en una aplicación Delphi?


¿Necesita mostrar una imagen GIF animada en una aplicación Delphi? Aunque
Delphi no admite formatos de archivos de imagen GIF de forma nativa (como BMP
o JPEG), hay algunos componentes geniales (fuente gratuita) disponibles en la
red, que agregan la capacidad de mostrar y manipular imágenes GIF en ejecución
y en tiempo de diseño. a cualquier aplicación Delphi.

De forma nativa, Delphi admite imágenes BMP, ICO, WMF y JPG, que pueden
cargarse en un componente compatible con gráficos (como TImage) y utilizarse en
una aplicación.

Nota: A partir de Delphi versión 2006, el formato GIF es compatible con el VCL.
Para utilizar imágenes GIF animadas, aún necesitaría un control de terceros.

GIF - Formato de intercambio de gráficos

GIF es el formato de gráficos más compatible (mapa de bits) en la Web, tanto para
imágenes fijas como para animaciones.

Usando en Delphi

Nativamente, Delphi (hasta la versión 2007) no admite imágenes GIF, debido a


algunos problemas legales de derechos de autor. Lo que esto significa es que
cuando suelta un componente TImage en un formulario, use el Editor de imágenes
(haga clic en el botón de puntos suspensivos en la columna Valor de las
propiedades, como la propiedad Imagen de TImage) para cargar una imagen en el
TImage, lo hará no tiene una opción para cargar imágenes GIF.
Afortunadamente, hay algunas implementaciones de terceros en Internet que
brindan soporte completo para el formato GIF:

▪ TGIFImage [1] - gratis con fuente (una versión de TGIFImage de Anders Melander
portada a Delphi 7). Implementación completa de TGraphic del formato de
gráficos GIF. Lee, escribe y muestra archivos GIF animados y transparentes, y
puede convertir a cualquier formato compatible con TGraphic (por ejemplo,
TBitmap, TJPEGImage, TIcon, TMetaFile, etc.). Implementa las especificaciones
completas GIF87a y GIF89a y las extensiones GIF más comunes. Las
características avanzadas incluyen:
▪ Se integra con TPicture para agregar compatibilidad GIF a los componentes
TImage, TOpenPictureDialog y TSavePictureDialog. También funciona en
tiempo de diseño.
▪ Importa imágenes con más de 256 colores utilizando la cuantización del
color y 6 diferentes métodos de difuminado (por ejemplo, floyd s! Teinberg).
▪ Motor de dibujo multihilo.
▪ El optimizador de GIF reduce el tamaño de tus GIF.
▪ Conversor GIF a AVI y AVI a GIF.

▪ Biblioteca de imágenes GraphicEx: una adición a Delphi's Graphics.pas para


permitir que su aplicación cargue muchos formatos de imagen comunes. Esta
biblioteca está diseñada principalmente para cargar imágenes como fondo
(botones, formularios, barras de herramientas) y texturas (DirectX, OpenGL) o
para fines de exploración y edición de imágenes, siempre que no necesite
guardar imágenes. Actualmente, solo TTargaGraphic también admite guardar
una imagen. GraphicEx es de código abierto bajo la Licencia Pública de Mozilla
(MPL).
Eso es todo. Ahora todo lo que tiene que hacer es descargar uno de los
componentes y comenzar a usar imágenes gif en sus aplicaciones.
Puedes, por ejemplo:

▪ Almacene imágenes GIF en una tabla de base de datos . Necesitarás los


"números mágicos" de la imagen GIF
▪ Mostrar gráficos GIF como Glifo en un SpeedButton
▪ Almacene gráficos GIF y un archivo HTML como recurso dentro de am exe

Dentro del EXE (Delphi)


• by Zarko Gajic

Almacenamiento de recursos (WAV, MP3, ...) en Delphi Executables

Los juegos y otros tipos de aplicaciones que usan archivos multimedia como
sonidos y animaciones deben distribuir los archivos multimedia adicionales junto
con la aplicación o insertar los archivos dentro del ejecutable.
En lugar de distribuir archivos separados para el uso de su aplicación, puede
agregar los datos sin formato a su aplicación como recurso. A continuación, puede
recuperar los datos de su aplicación cuando sea necesario.

Esta técnica es generalmente más deseable porque puede evitar que otros
manipulen esos archivos de complemento.

Este artículo le mostrará cómo incrustar (y usar) archivos de sonido,


videoclips, animaciones y, en general, cualquier tipo de archivo binario en
un ejecutable Delphi . Para el propósito más general, verás cómo poner un
archivo MP3 dentro de un exe Delphi.

Archivos de recursos (.RES)


En el artículo " Archivos de recursos hechos fáciles ", se le presentaron varios
ejemplos del uso de mapas de bits, iconos y cursores a partir de los recursos.
Como se indica en ese artículo, podemos usar el Editor de imágenes para crear y
editar recursos que constan de dichos tipos de archivos. Ahora, cuando estamos
interesados en almacenar varios tipos de archivos (binarios) dentro de un
ejecutable Delphi, tendremos que ocuparnos de los archivos de script de recursos
(.rc), la herramienta del compilador de recursos de Borland y otros.

La inclusión de varios archivos binarios en su ejecutable consta de 5 pasos:

1. Cree y / o recopile todos los archivos que desea poner en un exe,

1. Cree un archivo de script de recursos (.rc) que describa los recursos utilizados
por su aplicación.
2. Compile el archivo de archivo de script de recursos (.rc) para crear un archivo de
recursos (.res),
3. Enlace el archivo de recursos compilados en el archivo ejecutable de la
aplicación,
4. Use un elemento de recurso individual.
El primer paso debe ser simple, simplemente decida qué tipos de archivos desea
almacenar en su ejecutable.

Por ejemplo, almacenaremos dos canciones .wav, una animación .ani y una
canción .mp3.

Antes de continuar, aquí hay algunas afirmaciones importantes sobre las


limitaciones cuando se trabaja con recursos:

a) La carga y descarga de recursos no es una operación lenta. Los recursos son


parte del archivo ejecutable de las aplicaciones y se cargan al mismo tiempo que
se ejecuta la aplicación.

b) Toda la memoria (libre) se puede usar al cargar / descargar recursos. En otras


palabras, no hay límites en la cantidad de recursos cargados al mismo tiempo.

c) Por supuesto, el archivo de recursos duplica el tamaño de un ejecutable. Si


desea un ejecutable más pequeño, considere ubicar recursos y partes de su
proyecto en archivos DLL y paquetes .

Veamos ahora cómo crear un archivo que describa los recursos.

Crear un archivo de script de recursos (.RC)


Un archivo de script de recursos es simplemente un archivo de texto simple con la
extensión .rc que enumera los recursos. El archivo de script está en este formato:

ResName1 ResTYPE1 ResFileName1


ResName2 ResTYPE2 ResFileName2
...
ResNameX ResTYPEX ResFileNameX
...
RexName especifica un nombre único o un valor entero (ID) que identifica el
recurso. ResType describe el tipo de recurso y ResFileName es la ruta completa y
el nombre de archivo para el archivo de recursos individual.

Para crear un nuevo archivo de script de recursos, simplemente haga lo siguiente:

1. Crea un nuevo archivo de texto en tu directorio de proyectos.


2. Cambie el nombre a AboutDelphi.rc.
En el archivo AboutDelphi.rc, tenga las siguientes líneas:

Clock WAVE "c: \ mysounds \ projects \ clock.wav"


MailBeep WAVE "c: \ windows \ media \ newmail.wav"
Cool AVI cool.avi
Introducción RCDATA introsong.mp3
El archivo de script simplemente define los recursos. Siguiendo el formato dado, la
secuencia de comandos AboutDelphi.rc enumera dos archivos .wav, una
animación .avi y una canción .mp3. Todas las declaraciones en un archivo .rc
asocian un nombre identificativo, tipo y nombre de archivo para un recurso dado.
Hay alrededor de una docena de tipos de recursos predefinidos. Estos incluyen
iconos, mapas de bits, cursores, animaciones, canciones, etc. El RCDATA define
los recursos de datos genéricos. RCDATA le permite incluir un recurso de datos
en bruto para una aplicación. Los recursos de datos brutos permiten la inclusión
de datos binarios directamente en el archivo ejecutable.

Por ejemplo, la instrucción RCDATA anterior nombra el recurso binario Intro de la


aplicación y especifica el archivo introsong.mp3, que contiene la canción para ese
archivo mp3.

Nota: asegúrese de tener todos los recursos que lista en su archivo .rc disponible.
Si los archivos están dentro del directorio de proyectos, no es necesario que
incluya el nombre completo del archivo. En mi archivo .rc, las canciones .wav se
encuentran * en algún lugar * en el disco y tanto la animación como la canción
mp3 se encuentran en el directorio del proyecto.

Crear un archivo de recursos (.RES)


Para usar los recursos definidos en el archivo de script de recursos, debemos
compilarlo en un archivo .res con el compilador de recursos de Borland. El
compilador de recursos crea un nuevo archivo basado en el contenido del archivo
de script de recursos. Este archivo generalmente tiene una extensión .res. El
enlazador de Delphi volverá a formatear el archivo .res en un archivo de objeto de
recurso y luego lo vinculará al archivo ejecutable de una aplicación.

La herramienta de línea de comandos del compilador de recursos de Borland se


encuentra en el directorio Delphi Bin. El nombre es BRCC32.exe. Simplemente
vaya al símbolo del sistema y escriba brcc32 luego presione Enter. Dado que el
directorio Delphi \ Bin está en su ruta de acceso, se invoca el compilador Brcc32 y
muestra la ayuda de uso (ya que se llamó sin parapeters).

Para compilar el archivo AboutDelphi.rc en un archivo .res, ejecute este comando


en el símbolo del sistema (en el directorio de proyectos):

BRCC32 AboutDelphi.RC
De forma predeterminada, al compilar recursos, BRCC32 nombra el archivo de
recursos compilados (.RES) con el nombre base del archivo .RC y lo coloca en el
mismo directorio que el archivo .RC.

Puede asignarle al archivo de recursos todo lo que desee, siempre que tenga la
extensión ".RES" y el nombre del archivo sin la extensión no sea el mismo que el
de cualquier unidad o proyecto. Esto es importante porque, de forma
predeterminada, cada proyecto Delphi que se compila en una aplicación tiene un
archivo de recursos con el mismo nombre que el archivo del proyecto, pero con la
extensión .RES. Lo mejor es guardar el archivo en el mismo directorio que su
archivo de proyecto.

Incluir recursos (vincular / incorporar) a ejecutables

Con el compilador de recursos de Borland, hemos creado el archivo de recursos


AboutDelphi.res. El siguiente paso es agregar la siguiente directiva de compilación
a una unidad en su proyecto, inmediatamente después de la directiva de
formulario (debajo de la palabra clave de implementación). > {$ R * .DFM} {$ R
AboutDelphi.RES} No borre accidentalmente la parte {$ R * .DFM}, ya que esta es la
línea de código que le dice a Delphi que se vincule en la parte visual del formulario.
Cuando elige bitmaps para botones de velocidad, componentes de imagen o
componentes de botón, Delphi incluye el archivo de mapa de bits que eligió como
parte del recurso del formulario. Delphi aísla los elementos de su interfaz de
usuario en el archivo .DFM.
Una vez que el archivo .RES está vinculado al archivo ejecutable, la aplicación
puede cargar sus recursos en tiempo de ejecución según sea necesario. Para
utilizar realmente el recurso, tendrá que hacer algunas llamadas a la API de
Windows.
Para seguir el artículo necesitarás un nuevo proyecto Delphi con un formulario en
blanco (el nuevo proyecto predeterminado). Por supuesto, agregue la directiva {$
R AboutDelphi.RES} a la unidad del formulario principal. Finalmente es hora de ver
cómo usar recursos en una aplicación Delphi. Como se mencionó anteriormente,
para usar los recursos almacenados dentro de un archivo exe tenemos que lidiar
con API. Sin embargo, se pueden encontrar varios métodos en los archivos de
ayuda de Delphi que están habilitados para "recursos".

Por ejemplo, eche un vistazo al método LoadFromResourceName de un objeto


TBitmap.

Este método extrae el recurso de mapa de bits especificado y lo asigna objeto


TBitmap. Esto es * exactamente * lo que hace la llamada API de LoadBitmap.
Como siempre, Delphi ha mejorado una llamada de función API para satisfacer
mejor sus necesidades.

Reproducción de animaciones de recursos

Para mostrar la animación dentro de cool.avi (recuerde que se definió en el archivo


.rc), usaremos el componente TAnimate (paleta de Win32), suéltelo en el formulario
principal. Deje que el nombre del componente de Animate sea el predeterminado:
Animate1. Utilizaremos el evento OnCreate de un formulario para mostrar la
animación: > procedure TForm1.FormCreate (Sender:
TObject); comenzar con Animate1 do begin ResName: = 'cool'; ResHandle: =
hInstance; Activo: = VERDADERO; fin ; fin ; ¡Así de simple! Como podemos ver, para
reproducir una animación de un recurso tenemos que utilizar las propiedades
ResHandle, ResName o ResID del componente TAnimate. Después de configurar
ResHandle, establecemos la propiedad ResName para especificar qué recurso es el
clip AVI que debe mostrar el control de animación. Al asentarse como verdadero
en la propiedad activa, simplemente comienza la animación.

Jugando WAVs

Como hemos colocado dos archivos WAVE en nuestro archivo ejecutable, ahora
veremos cómo tomar una canción dentro del archivo ejecutable. Coloque un botón
(Button1) en un formulario y asigne el siguiente código al controlador de eventos
OnClick: > usa mmsystem; ... procedimiento TForm1.Button1Click (Sender:
TObject); var hFind, hRes: THandle; Canción: PChar; begin hFind: = FindResource
(HInstance, 'MailBeep', 'WAVE'); si hFind <> 0 entonces comienza hRes: =
LoadResource (HInstance, hFind); si hRes <> 0 entonces comienza Song: =
LockResource (hRes); si se asigna (canción), luego SndPlaySound (canción,
snd_ASync o snd_Memory); UnlockResource (hRes); fin ; FreeResource
(hFind); fin ; fin ; Este enfoque usa varias llamadas API para cargar un recurso de
tipo WAVE llamado MailBeep y reproducirlo. Nota: tu cal utiliza Delphi para
reproducir sonidos predefinidos del sistema.

Reproducción de MP3

El único archivo MP3 en nuestro recurso tiene el nombre Intro. Dado que este
recurso es del tipo RCDATA, utilizaremos otra técnica para obtener y reproducir la
canción mp3. En caso de que no sepa que Delphi puede reproducir canciones MP3,
lea el artículo " Cree su propio WinAmp ". Sí, así es, TMediaPlayer puede reproducir
el archivo mp3.
Ahora, agregue el componente TMediaPlayer a un formulario (nombre:
MediaPlayer1) y agregue un TButton (Button2). Deje que el evento OnClick se vea
así:

> procedure TForm1.Button2Click (Sender: TObject); var rStream:


TResourceStream; fStream: TFileStream; fname: cadena; begin {esta parte extrae el
mp3 de exe} fname: = ExtractFileDir (Paramstr (0)) + 'Intro.mp3'; rStream: =
TResourceStream.Create (hInstance, 'Intro', RT_RCDATA); prueba fStream: =
TFileStream.Create (fname, fmCreate); prueba fStream.CopyFrom (rStream,
0); finalmente fStream.Free; fin ; finalmente rStream.Free; fin ; {esta parte
reproduce el mp3} MediaPlayer1.Close; MediaPlayer1.FileName: =
fname; MediaPlayer1.Open; fin ; Este código, con la ayuda de TResourceStream,
extrae la canción mp3 del exe y la guarda en el directorio de trabajo de las
aplicaciones. El nombre del archivo mp3 es intro.mp3. Luego simplemente asigne
ese archivo a la propiedad FileName de un MediaPlayer y reproduzca la canción.
Un problema menor * es que la aplicación crea una canción mp3 en una máquina
de usuario. Puede agregar un código que borre ese archivo antes de que la
aplicación finalice.

Extrayendo *. ???

Por supuesto, cualquier otro tipo de archivo binario se puede almacenar como un
tipo de RCDATA. El TRsourceStream está diseñado especialmente para ayudarnos a
extraer dicho archivo de un ejecutable. Las posibilidades son infinitas: HTML en un
exe, EXE en exe, base de datos vacía en un exe, ....

Comprender y usar los punteros en


Delphi
• by Zarko Gajic
• Una introducción a los indicadores y su uso para principiantes Delphi
• A pesar de que los punteros no son tan importantes en Delphi como lo son
en C o C ++, son una herramienta tan "básica" que casi todo lo que tiene
que ver con la programación debe tratar con los punteros de alguna
manera.

• Es por esa razón que puede leer acerca de cómo una cadena u objeto es
realmente solo un puntero, o que un controlador de eventos como OnClick,
en realidad es un puntero a un procedimiento.

• Puntero al tipo de datos


• En pocas palabras, un puntero es una variable que contiene la dirección de
cualquier cosa en la memoria.

• Para concretar esta definición, tenga en cuenta que todo lo que usa una
aplicación se almacena en algún lugar de la memoria de la computadora.
Como un puntero contiene la dirección de otra variable, se dice que apunta
a esa variable.

• La mayoría de las veces, los punteros en Delphi apuntan a un tipo


específico:

• > var iValue, j: entero ; pIntValue: ^ entero; begin iValue: = 2001; pIntValue: =
@iValue; ... j: = pIntValue ^; fin ;

• La sintaxis para declarar un tipo de datos de puntero utiliza un símbolo de


intercalación (^) . En el código anterior, iValue es una variable de tipo entero
y pIntValue es un puntero de tipo entero. Como un puntero no es más que
una dirección en la memoria, debemos asignarle la ubicación (dirección) del
valor almacenado en la variable entera de iValue.

• El operador @ devuelve la dirección de una variable (o una función o


procedimiento como se verá a continuación). Equivalente al operador @ es
la función Addr . Tenga en cuenta que el valor de pIntValue no es 2001.

• En este código de ejemplo, pIntValue es un puntero entero tipado. Un buen


estilo de programación es utilizar punteros tipeados tanto como sea posible.
El tipo de datos del puntero es un tipo de puntero genérico; representa un
puntero a cualquier dato.

• Tenga en cuenta que cuando "^" aparece después de una variable de


puntero, desreferencia el puntero; es decir, devuelve el valor almacenado
en la dirección de memoria mantenida por el puntero.

• En este ejemplo, la variable j tiene el mismo valor que iValue. Podría


parecer que esto no tiene ningún sentido cuando simplemente podemos
asignar iValue a j, pero este fragmento de código se encuentra detrás de la
mayoría de las llamadas a Win API.
• Indicadores NILing
• Los punteros no asignados son peligrosos. Como los punteros nos permiten
trabajar directamente con la memoria de la computadora, si intentamos (por
error) escribir en una ubicación protegida en la memoria, podríamos obtener
un error de violación de acceso. Esta es la razón por la que siempre
debemos inicializar un puntero a NIL.

• NIL es una constante especial que se puede asignar a cualquier puntero.


Cuando se asigna nil a un puntero, el puntero no hace referencia a nada.
Delphi presenta, por ejemplo, una matriz dinámica vacía o una cadena larga
como un puntero nulo.

• Punteros de personaje
• Los tipos fundamentales PAnsiChar y PWideChar representan punteros a
los valores de AnsiChar y WideChar. El PChar genérico representa un
puntero a una variable Char.

• Estos punteros de caracteres se utilizan para


manipular cadenas terminadas en nulo. Piense en un PChar como un
puntero a una cadena terminada en nulo o a la matriz que representa una.

• Punteros a los registros


• Cuando definimos un registro u otro tipo de datos, es una práctica común
también definir un puntero a ese tipo. Esto hace que sea más fácil
manipular instancias del tipo sin copiar bloques grandes de memoria.

• La capacidad de tener punteros a registros (y matrices) hace que sea


mucho más fácil configurar estructuras de datos complicadas como listas y
árboles vinculados.

• > escriba pNextItem = ^ TLinkedListItem TLinkedListItem = record sName:


String; iValue: Entero; NextItem: pNextItem; fin ;

• La idea detrás de las listas enlazadas es darnos la posibilidad de almacenar


la dirección en el próximo elemento vinculado en una lista dentro de un
campo de registro NextItem.

• Los punteros a los registros también se pueden usar cuando se almacenan


datos personalizados para cada elemento de vista de árbol, por ejemplo.

• Consejo: para obtener más información sobre estructuras de datos,


considere el libro The Tomes of Delphi: Algorithms and Data Structures.

• Punteros procedimentales y metodológicos


• Otro concepto importante de puntero en Delphi es el procedimiento y los
punteros del método.
• Los punteros que apuntan a la dirección de un procedimiento o función se
llaman punteros de procedimiento.

• Los punteros de método son similares a los punteros de procedimiento. Sin


embargo, en lugar de apuntar a procedimientos independientes, deben
apuntar a métodos de clase.

• El puntero de método es un puntero que contiene información sobre el


nombre y el objeto que se invoca.

• Punteros y API de Windows


• El uso más común para los punteros en Delphi es la interfaz con el código
C y C ++, que incluye el acceso a la API de Windows.

• Las funciones de API de Windows usan una cantidad de tipos de datos que
pueden ser desconocidos para el programador Delphi. La mayoría de los
parámetros en las funciones de API de llamada son indicadores de algún
tipo de datos. Como se indicó anteriormente, usamos cadenas terminadas
en nulo en Delphi cuando llamamos a funciones de la API de Windows.

• En muchos casos, cuando una llamada API devuelve un valor en un búfer o


puntero a una estructura de datos, la aplicación debe asignar estos búferes
y estructuras de datos antes de realizar la llamada API. La función
SHBrowseForFolder API de Windows es un ejemplo.

• Puntero y asignación de memoria


• El verdadero poder de los punteros proviene de la capacidad de reservar
memoria mientras el programa se está ejecutando.

• Este fragmento de código debería ser suficiente para demostrar que


trabajar con punteros no es tan difícil como podría parecer al principio. Se
usa para cambiar el texto (título) del control con el asa proporcionada.

• > procedimiento GetTextFromHandle (hWND: THandle); var pText: PChar; // un


puntero a char (ver arriba) TextLen: entero; begin {obtener la longitud del
texto} TextLen: = GetWindowTextLength (hWND); {alocate memory} GetMem (pText,
TextLen); // toma un puntero {obtiene el texto del control} GetWindowText (hWND,
pText, TextLen + 1); {mostrar el texto} ShowMessage (String (pText)) {liberar la
memoria} FreeMem (pText); fin ;
Manejo de errores y excepciones en
aplicaciones Delphi
• by Zarko Gajic
• ¡La línea de código más libre de errores es la que no tiene que escribir!

• Desafortunadamente, la construcción de aplicaciones incluye codificación.


Independientemente de cuán cuidadosamente escriba / depure su
programa, será imposible imaginar cada situación que pueda salir mal. El
usuario inexperto podría, por ejemplo, intentar abrir un archivo inexistente o
ingresar un valor incorrecto en un campo de datos.
Los usuarios cometen errores y debemos estar preparados para manejar /
prevenir estos errores donde sea y cuando sea posible.

• Errores, Excepciones?
• Una excepción generalmente es una condición de error u otro evento que
interrumpe el flujo normal de ejecución en una aplicación. Cuando se
produce un error al procesar una línea de código, Delphi crea (aumenta) un
descendiente de objeto de TObject llamado objeto de excepción.

• Bloques guardados
• Una aplicación responde a una excepción ejecutando un código de
terminación, manejando la excepción o ambas. La forma de habilitar la
captura de error / excepción dentro de un código dado, la excepción debe
ocurrir dentro de un bloque de instrucciones oculto. El código general se ve
así:

• > prueba {bloque de código guardado} excepto en do begin {exception block-


handleles SomeException} end; fin;

• Una instrucción try / except ejecuta las instrucciones en el bloque de


código protegido. Si las instrucciones se ejecutan sin que se genere
ninguna excepción, se ignora el bloque de excepción y el control pasa a la
instrucción que sigue a la palabra clave final.

• Ejemplo:

• > ... Cero: = 0; try dummy: = 10 / Zero; excepto en EZeroDivide do MessageDlg ('No
se puede dividir por cero!', mtError, [mbOK], 0); fin; ...

• Protección de recursos
• Cuando una sección de código adquiere un recurso, a menudo es
necesario garantizar que el recurso se libera nuevamente (o puede tener
una fuga de memoria ), independientemente de si el código se completa
normalmente o si se interrumpe con una excepción.
• En este caso, la sintaxis utiliza finalmente la palabra clave y se ve así:

• > {algún código para asignar recursos} intente {bloque de código guardado}
finalmente {bloque de terminación - código para liberar recursos} final;

• Ejemplo:

• > ... AboutBox: = TAboutBox.Create (nil); prueba AboutBox.ShowModal; finalmente


AboutBox.Release; fin; ...

• Application.OnException
• Si su aplicación no maneja el error que causó la excepción, Delphi usará su
manejador de excepción predeterminado: aparecerá un cuadro de mensaje.
Puede considerar escribir código en el evento OnException para el objeto
TApplication, para atrapar errores en el nivel de la aplicación.

• Break On Exceptions
• Al crear un programa con manejo de excepciones, es posible que no desee
que Delphi incumpla las Excepciones. Esta es una gran característica si
desea que Delphi muestre dónde se ha producido una excepción; sin
embargo, puede ser molesto cuando prueba su propio manejo de
excepciones.

• Pocas palabras finales


• La idea de este artículo es darle una rápida mirada a las excepciones. Para
una discusión más detallada sobre el manejo de excepciones, considere
el Manejo de excepciones en el manejo de excepciones de Delphi , usando
una herramienta como Delphi Crash / Exception Handling con Bug
Reporting y algunos de los siguientes artículos relacionados:

Las 4 mejores herramientas de informes


de Delphi
• by Zarko Gajic
• Estas herramientas de informes superiores de Delphi crean fácilmente
informes complejos que enlazan directamente con un EXE de Delphi. Las
herramientas incluyen un motor de informes, diseñador de informes y un
ejecutor de pruebas.

• 01 de 04

• FastReport
• FastReport es un componente adicional que le da a la aplicación la
capacidad de generar informes de manera rápida y eficiente. FastReport
proporciona todas las herramientas necesarias para desarrollar informes,
incluido un motor de informes, diseñador de informes, vista previa,
diseñador de cuadros de diálogo y macrointerpreta tipo Pascal. Con
FastReport, puede desarrollar informes que satisfagan sus necesidades
multiplataforma para Windows y Linux. Más "

• 02 de 04

• Informes Rave
• Los Informes Rave combinan los requisitos esenciales con el entorno de
diseño visual más fácil pero más potente disponible. El sistema de informes
basado en código contiene 19 componentes con más de 500 métodos,
propiedades y eventos, y se compila en su aplicación sin archivos externos.
Algunas de sus características incluyen memos envueltos en palabras,
gráficos completos, justificación y posicionamiento preciso de la página.
Más "

• 03 de 04

• QuickReport
• QuickReport es un generador de informes con bandas escrito en código
100% Delphi. ¡QuickReport se integra con Delphi y C ++ Builder casi al
extremo! Diseñe informes dentro de Delphi IDE, utilizando el familiar
diseñador de formularios como diseñador de informes. QuickReport es tan
fácil de usar, rápido y potente que Borland elige usarlo como la herramienta
de informes estándar para Delphi y C ++ Builder. Más "

• 04 de 04

• Motor de impresión virtual


• La dinámica de VPE para Windows crea documentos para la salida de
pantalla y de la impresora llamando funciones durante el tiempo de
ejecución de una aplicación. El posicionamiento libre de objetos gráficos
(por ejemplo, texto, imágenes, líneas, etc.) por código ofrece opciones de
diseño ilimitadas. Use VPE para crear informes y listas, así como para
completar documentos y formularios. Más "

Comprender el parámetro del remitente


en Delphi Event Handlers
• by Zarko Gajic

Manejadores de eventos y el remitente


Eche un vistazo al siguiente controlador de eventos para el evento OnClick de un
botón (llamado "Button1"): > procedure TForm1.Button1Click ( Sender :
TObject); comenzar ... finalizar ; El método Button1Click toma un puntero a un
TObject llamado Sender. Cada controlador de eventos, en Delphi, tendrá al menos
un parámetro de remitente. Cuando se hace clic en el botón, se llama al
controlador de eventos (Button1Click) para el evento OnClick .
El parámetro "Remitente" hace referencia al control que se utilizó para llamar al
método.

Si hace clic en el control Button1, haciendo que se llame al método Button1Click,


se pasa una referencia o puntero al objeto Button1 a Button1Click en el parámetro
llamado Sender.

Compartamos un poco de código

El parámetro Sender, cuando se usa correctamente, puede brindar una cantidad


increíble de flexibilidad en nuestro código. Lo que hace el parámetro Sender es
saber qué componente desencadenó el evento. Esto facilita el uso del mismo
controlador de eventos para dos componentes diferentes.
Por ejemplo, supongamos que queremos tener un botón y un elemento de menú
para hacer lo mismo. Sería una tontería tener que escribir el mismo controlador de
eventos dos veces.

Para compartir un controlador de eventos en Delphi, haga lo siguiente:

1. Escriba el controlador de eventos para el primer objeto (por ejemplo, botón en


la barra de acceso rápido)
2. Seleccione el nuevo objeto u objetos, sí, más de dos pueden compartir (por
ejemplo, MenuItem1)
3. Vaya a la página del evento en el Inspector de Objetos.
4. Haga clic en la flecha hacia abajo junto al evento para abrir una lista de
controladores de eventos escritos anteriormente. (Delphi le dará una lista de
todos los controladores de eventos compatibles que existen en el formulario)

1. Seleccione el evento de la lista desplegable. (por ejemplo, Button1Click)


Lo que hemos hecho aquí es crear un único método de manejo de eventos que
maneje el evento OnClick tanto de un botón como de un elemento del menú.
Ahora, todo lo que tenemos que hacer (en este controlador de eventos
compartidos) es distinguir qué componente llamó al controlador. Por ejemplo,
podríamos tener un código como este: > procedure TForm1.Button1Click (Sender:
TObject); begin {código tanto para un botón como para un elemento de
menú} ... {algún código específico:} si Sender = Button1 luego ShowMessage
('Button1 clicked!') else si Sender = MenuItem1 luego ShowMessage ('MenuItem1
hecho clic!') else ShowMessage ('??? clicked!'); fin ; En general, verificamos si el
emisor es igual al nombre del componente.
Nota: el segundo más en la instrucción if-then-else maneja la situación cuando ni
el Button1 ni el MenuItem1 han causado el evento. Pero, quién más podría llamar
al controlador, podrías preguntar. Pruebe esto (necesitará un segundo botón:
Button2):

> procedure TForm1.Button2Click (Sender: TObject); Comience Button1Click


(Button2); {esto dará como resultado: '??? hecho clic! '} fin ;

IS y AS

Como el remitente es del tipo TObject, cualquier objeto se puede asignar al


remitente. El valor de Sender siempre es el control o componente que responde al
evento. Podemos probar al remitente para encontrar el tipo de componente o
control que llamó al controlador de eventos utilizando la palabra reservada. Por
ejemplo, > si
el remitente es TButton, luego DoSomething else DoSomethingElse ; Para rayar la
superficie de los operadores "is" y "as", agregue un cuadro de edición (llamado
Edit1) al formulario y coloque el siguiente código en el controlador de eventos
OnExit: > procedure TForm1.Edit1Exit (Sender: TObject); comenzar Button1Click
(Edit1); fin ; Ahora cambie ShowMessage ('??? clicked!'); parte en el controlador de
eventos Button1 OnClick para: > {... else} comenzar si el remitente es TButton
y luego ShowMessage ('¡Algún otro botón activó este evento!') else si
el remitente es TEdit y luego el remitente como TEdit comienza Text: = ' Edit1Exit
ha sucedido '; Ancho: = ancho * 2; Altura: = Altura * 2; fin {comenzar con} fin ; Ok,
veamos: si hacemos clic en el Botón1, ¡el 'Botón1 hizo clic!' aparecerá, si hacemos
clic en el MenuItem1, se hace clic en 'MenuItem1!' aparecerá. Sin embargo, si
hacemos clic en Buton2, el botón '¡Otro botón activó este evento!' aparecerá un
mensaje, pero ¿qué pasará cuando salga del cuadro Editar1? Te dejaré esto a ti.

Conclusión

Como podemos ver, el parámetro del remitente puede ser muy útil cuando se usa
correctamente. Supongamos que tenemos un montón de cuadros de edición y
etiquetas que comparten el mismo controlador de eventos. Si queremos saber
quién desencadenó el evento y actuar, tendremos que tratar con las variables
Object. Pero, dejemos esto para alguna otra ocasión.
Cómo agregar los principales ceros a un
número (formato Delphi)
• by Zarko Gajic
• Las diferentes aplicaciones requieren valores específicos para ajustarse a
los paradigmas estructurales. Por ejemplo, los números de la Seguridad
Social siempre tienen nueve dígitos de largo. Algunos informes requieren
que los números se muestren con una cantidad fija de caracteres. Los
números de secuencia, por ejemplo, generalmente comienzan con 1 y se
incrementan sin fin, por lo que se muestran con ceros a la izquierda para
presentar un atractivo visual.

• Como programador de Delphi , su enfoque para rellenar un número con


ceros a la izquierda depende del caso de uso específico para ese valor.

• Simplemente puede optar por rellenar un valor de visualización, o puede


convertir un número en una cadena para el almacenamiento en una base
de datos.

• Mostrar el método de relleno


• Use una función directa para cambiar la forma en que se muestra su
número. Utilice el formato para realizar la conversión proporcionando un
valor de longitud (la longitud total del resultado final) y el número que desea
rellenar:

• > str: = Formato ('%. * d, [longitud, número])

• Para rellenar el número 7 con dos ceros a la izquierda, inserte esos valores
en el código:

• > str: = Formato ('%. * d, [3, 7]);

• El resultado es 007 con el valor devuelto como una cadena.

• Convertir a método de cadena


• Utilice una función de relleno para agregar los ceros a la izquierda (o
cualquier otro carácter) cada vez que lo necesite dentro de su secuencia de
comandos. Para convertir valores que ya son enteros, use:

• > función LeftPad (valor: entero; longitud: entero = 8; pad: char = '0'):
cadena; sobrecarga; begin result: = RightStr (StringOfChar (pad, length) + IntToStr
(value), length); fin;

• Si el valor que se convertirá ya es una cadena, use:


• > función LeftPad (valor: cadena; longitud: entero = 8; pad: char = '0'):
cadena; sobrecarga; begin result: = RightStr (StringOfChar (pad, longitud) + valor,
longitud); fin;

• Este enfoque funciona con Delph i 6 y ediciones posteriores. Ambos


bloques de código tienen por defecto un carácter de relleno de 0 con una
longitud de siete personajes devueltos; esos valores pueden ser
modificados para satisfacer sus necesidades.

• Cuando se llama a LeftPad, devuelve los valores de acuerdo con el


paradigma especificado. Por ejemplo, si establece un valor entero en 1234,
llamando a LeftPad:

• i: = 1234;
r: = LeftPad (i);

• devolverá un valor de cadena de 0001234

Componentes principales de Dephi para


acceder a MySQL
• by Zarko Gajic
• Una descripción general de los componentes de VCL que le permite acceder a una
base de datos MySQL desde Delphi utilizando controles de datos estándar sin
utilizar BDE / ADO / ODBC. Además de algunas herramientas relacionadas con
MYSQL. MySQL es un servidor de base de datos de código abierto confiable,
rápido, compacto, potente y multiplataforma de código abierto.

• 01 de 07

• Componentes de acceso a datos para MySQL


• Data Access Components para MySQL (MyDAC) es una biblioteca de componentes
que proporciona acceso directo a servidores de bases de datos MySQL desde
Delphi, Delphi para .NET, C ++ Builder y Kylix. MyDAC se puede conectar
directamente al servidor MySQL o trabajar a través de la biblioteca del cliente
MySQL. Más "

• 02 de 07

• TmySQL
• TmySQL proporciona acceso a servidores MySQL desde Delphi a través de un
componente visual y un componente no visual extensible. TmySQL utiliza una única
DLL de cliente, que es proporcionada por la mayoría de las versiones de MySQL
compiladas en Windows. TmySQL no utiliza los componentes de la base de datos
en Delphi, como TDatabase, TQuery, etc. Open Source. Más "

• 03 de 07

• MySQLDAC
• MySQLDAC es el reemplazo de MySQL BDE. Este conjunto de componentes
permite crear aplicaciones Delphi con acceso directo a MySQL DB sin BDE y ODBC.
Los campos BLOB son compatibles. MySQLDAC fue desarrollado para facilitar la
migración de proyectos existentes desde el esquema BDE / ODBC al nativo. El
componente TDBImageEx para compatibilidad con imágenes JPEG está incluido en
el paquete de forma gratuita (con fuentes). MySQLDAC es un producto libre de
regalías. Más "

• 04 de 07

• Controladores ODBC de MySQL


• Los controladores ODBC de MySQL le permiten conectarse a MySQL
ejecutándose en su servidor privado virtual desde su PC e importar /
exportar bases de datos. Herramienta práctica para exportar una base de
datos MS Access a MySQL y viceversa. Más "

• 05 de 07

• Componentes MySQL
• El TMySQLComponents consiste en TMySQLServer y TMySQLDataset. El objetivo de
estos componentes es brindarle acceso directo a todas las características del
servidor MySQL utilizando los controles estándar de datos en Delphi o Kylix sin las
limitaciones de BDE o dbExpress. Los componentes son de fuente única y se
compilarán en Delphi 5/6 o Kylix 1/2 utilizando los mismos archivos fuente.
Comercial. Más "

• 06 de 07

• SQL directo
• La idea principal del proyecto es tener componentes nativos delphi multiplataforma
(Windows + Linux) para acceder directamente a los servidores SQL (sin utilizar
ningún dll externall). El primer lanzamiento será para My-sql e Interbase, pero hay
planes para ser extendend. Licencia pública general de GNU. Más "

• 07 de 07

• Biblioteca Zeos
• Componentes para un acceso rápido a MySql, PostgreSql, MicrosoftSQL, Oracle e
Interbase SQL sin usar complementos, como BDE / ODBC / ADO. Además, los
componentes: las fuentes de datos son compatibles con el TDataset estándar y
tienen varias funciones adicionales. Fuente abierta. Más "

Edición de hojas de Excel con Delphi y


ADO
• by Zarko Gajic

Métodos para transferir datos entre Excel y Delphi

Esta guía paso a paso describe cómo conectarse a Microsoft Excel, recuperar
datos de hojas y habilitar la edición de los datos utilizando DBGrid. También
encontrará una lista de los errores más comunes que pueden aparecer en el
proceso, además de cómo tratarlos.

Lo que está cubierto a continuación:

▪ Métodos para transferir datos entre Excel y Delphi . Cómo conectarse a Excel
con ADO (ActiveX Data Objects) y Delphi.
▪ Crear un editor de hoja de cálculo Excel usando Delphi y ADO

▪ Recuperando los datos de Excel. Cómo hacer referencia a una tabla (o rango) en
un libro de Excel.
▪ Una discusión sobre los tipos de campo Excel (columna)
▪ Cómo modificar hojas de Excel: edita, agrega y elimina filas.
▪ Transferencia de datos de una aplicación Delphi a Excel. Cómo crear una hoja
de trabajo y llenarla con datos personalizados de una base de datos de MS
Access.

Cómo conectarse a Microsoft Excel

Microsoft Excel es una poderosa herramienta de análisis de datos y calculadora de


hoja de cálculo. Dado que las filas y columnas de una hoja de trabajo de Excel se
relacionan estrechamente con las filas y columnas de una tabla de base de datos,
muchos desarrolladores encuentran apropiado transportar sus datos a un libro de
trabajo de Excel para fines de análisis; y recuperar datos a la aplicación después.

El enfoque más utilizado para el intercambio de datos entre su aplicación y Excel


es la automatización . La automatización proporciona una forma de leer datos de
Excel utilizando el Modelo de objetos de Excel para sumergirse en la hoja de
trabajo, extraer sus datos y mostrarlos dentro de un componente similar a una
cuadrícula, concretamente DBGrid o StringGrid.

La automatización le brinda la mayor flexibilidad para ubicar los datos en el libro


de trabajo, así como también la capacidad de formatear la hoja de trabajo y
realizar diversas configuraciones en tiempo de ejecución.

Para transferir sus datos ay desde Excel sin automatización, puede usar otros
métodos como:

▪ Escriba datos en un archivo de texto delimitado por comas y deje que Excel
analice el archivo en celdas

▪ Transfiera datos usando DDE (intercambio dinámico de datos)


▪ Transfiera sus datos hacia y desde una hoja de trabajo usando ADO

Transferencia de datos usando ADO

Como Excel es compatible con JET OLE DB, puede conectarse con Delphi usando
ADO (dbGO o AdoExpress) y luego recuperar los datos de la hoja de cálculo en un
conjunto de datos ADO emitiendo una consulta SQL (del mismo modo que abriría
un conjunto de datos contra cualquier tabla de base de datos) .

De esta forma, todos los métodos y características del objeto ADODataset están
disponibles para procesar los datos de Excel. En otras palabras, el uso de los
componentes de ADO le permite crear una aplicación que puede usar un libro de
Excel como base de datos. Otro hecho importante es que Excel es un servidor
ActiveX fuera de proceso. ADO se ejecuta en proceso y ahorra la sobrecarga de
costosas llamadas fuera de proceso.

Cuando se conecta a Excel utilizando ADO, solo puede intercambiar datos sin
procesar desde y hacia un libro de trabajo. Una conexión ADO no se puede usar
para formatear hojas o implementar fórmulas en celdas. Sin embargo, si transfiere
sus datos a una hoja de trabajo preformateada, se conserva el formato. Después
de insertar los datos desde su aplicación a Excel, puede llevar a cabo cualquier
formateo condicional utilizando una macro (pregrabada) en la hoja de trabajo.

Puede conectarse a Excel utilizando ADO con los dos proveedores OLE DB que
forman parte de MDAC: proveedor Microsoft Jet OLE DB o proveedor Microsoft
OLE DB para controladores ODBC.

Nos centraremos en el proveedor Jet OLE DB, que se puede usar para acceder a
los datos en los libros de Excel a través de los controladores instalados del
Método de acceso secuencial indexado (ISAM).
Consejo: consulte el Curso de principiantes para la Programación de bases de
datos ADO de Delphi si es nuevo en ADO.

The ConnectionString Magic

La propiedad ConnectionString le dice a ADO cómo conectarse a la fuente de


datos. El valor utilizado para ConnectionString consiste en uno o más argumentos
que ADO usa para establecer la conexión.

En Delphi, el componente TDOConnection encapsula el objeto de conexión ADO;


puede ser compartido por múltiples componentes del conjunto de datos ADO
(TADOTable, TADOQuery, etc.) a través de sus propiedades de conexión.

Para conectarse a Excel, una cadena de conexión válida solo implica dos piezas
adicionales de información: la ruta completa al libro de trabajo y la versión del
archivo de Excel.

Una cadena de conexión legítima podría verse así:

ConnectionString: = 'Provider = Microsoft.Jet.OLEDB.4.0; Data Source = C: \


MyWorkBooks \ myDataBook.xls; Propiedades extendidas = Excel 8.0;';
Al conectarse a un formato de base de datos externo admitido por el Jet, es
necesario establecer las propiedades extendidas para la conexión. En nuestro
caso, cuando se conecta a una "base de datos" de Excel, las propiedades
extendidas se utilizan para establecer la versión del archivo de Excel.

Para un libro de Excel95, este valor es "Excel 5.0" (sin las comillas); utilice "Excel
8.0" para Excel 97, Excel 2000, Excel 2002 y ExcelXP.

Importante: debe usar el proveedor de Jet 4.0 ya que Jet 3.5 no es compatible
con los controladores de ISAM. Si configura el proveedor de Jet en la versión 3.5,
recibirá el error "No se pudo encontrar ISAM instalable".

Otra propiedad extendida de Jet es "HDR =". "HDR = Sí" significa que hay una fila
de encabezado en el rango, por lo que el Jet no incluirá la primera fila de la
selección en el conjunto de datos. Si se especifica "HDR = No", el proveedor
incluirá la primera fila del rango (o rango con nombre) en el conjunto de datos.

La primera fila en un rango se considera la fila del encabezado por defecto ("HDR
= Yes"). Por lo tanto, si tiene un encabezado de columna, no necesita especificar
este valor. Si no tiene encabezados de columna, debe especificar "HDR = No".

Ahora que ya está listo, esta es la parte donde las cosas se vuelven interesantes
ya que ahora estamos listos para algún código. Veamos cómo crear un editor de
hoja de cálculo Excel simple usando Delphi y ADO.
Nota: debe continuar aunque no tenga conocimiento de la programación de ADO
y Jet.

Como verá, editar un libro de Excel es tan simple como editar datos desde
cualquier base de datos estándar.

Seleccionar y resaltar una fila en un


DBGrid
• by Zarko Gajic
• ¿Alguna vez ha visto un menú o columna de tabla / resaltado de fila con un
color diferente cuando el mouse se desplaza sobre él? Ese es nuestro
objetivo aquí: hacer que una fila se destaque cuando el puntero del mouse
esté dentro del alcance.

• El componente TDBGrid Delphi es una de las joyas del VCL. Diseñado para
permitir a un usuario ver y editar datos en una cuadrícula tabular, DBGrid
proporciona varias formas de personalizar la forma en que representa sus
propios datos.

• Por ejemplo, agregar color a las cuadrículas de su base de datos mejorará


la apariencia y diferenciará la importancia de ciertas filas o columnas dentro
de la base de datos.

• Sin embargo, no se deje engañar por tutoriales demasiado simplistas sobre


este tema. Puede parecer fácil establecer simplemente la
propiedad dgRowSelect , pero recuerde que cuando se
incluye dgRowSelect en Opciones , el indicador dgEditing se ignora, lo que
significa que la edición de los datos mediante la cuadrícula está
desactivada.

• Lo que encontrará a continuación es una explicación sobre cómo habilitar el


tipo de evento OnMouseOver para una fila DBGrid, de modo que el mouse
esté registrado y ubicado, activando el registro para resaltar la fila
correspondiente en un DBGrid.

• Cómo trabajar con OnMouseOver


• El primer orden del día es escribir código para el evento OnMouseMove en
un componente TDBGrid para que pueda ubicar la fila y columna (celda) de
DBGrid sobre la que se encuentra el mouse.

• Si el mouse está sobre la grilla (manejado en el controlador de


eventos OnMouseMove ), puede usar el método MoveBy de un
componente DataSet para establecer el registro actual en el que se muestra
"debajo" del cursor del mouse.
• tipo THackDBGrid = clase (TDBGrid);
... procedimiento TForm1.DBGrid1MouseMove (Sender: TObject; Shift: TShiftState;
X, Y: Integer); var gc: TGridCoord; begin gc: = DBGrid1.MouseCoord (x, y); if (gc.X>
0) AND (gc.Y> 0) entonces comienza DBGrid1.DataSource.DataSet.MoveBy (gc.Y -
THackDBGrid (DBGrid1) .Row); fin ; fin ;

• Nota: Se puede usar un código similar para mostrar en qué celda se


encuentra el mouse y para cambiar el cursor cuando está sobre la barra de
título.

• Para establecer correctamente el registro activo, debe hackear un DBGrid y


poner sus manos en la propiedad Row protegida. La propiedad Row de un
componente TCustomDBGrid contiene la referencia a la fila actualmente
activa.

• Muchos componentes de Delphi tienen propiedades y métodos útiles que


se marcan como invisibles o protegidos para un desarrollador de Delphi.
Con suerte, para acceder a dichos miembros protegidos de un componente,
se puede utilizar una técnica simple llamada "hack protegido".

• Con el código anterior, cuando mueve el mouse sobre la cuadrícula, el


registro seleccionado es el que se muestra en la cuadrícula "debajo" del
cursor del mouse. No es necesario hacer clic en la cuadrícula para cambiar
el registro actual.

• Haga resaltar la fila activa para mejorar la experiencia del usuario:

• procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect;


DataCol: Entero; Columna: TColumn; Estado:
TGridDrawState); begin if (THackDBGrid (DBGrid1) .DataLink.ActiveRecord + 1 =
THackDBGrid (DBGrid1) .Row) o (gdFocused en State) o (gdSelected in
State) luego comience DBGrid1.Canvas.Brush.Color: = clSkyBlue;
DBGrid1.Canvas.Font.Style: = DBGrid1.Canvas.Font.Style + [fsBold];
DBGrid1.Canvas.Font.Color: = clRed; fin ; fin ;

• El evento OnDrawColumnCell se usa para manejar la necesidad de un


dibujo personalizado para los datos en las celdas de la grilla.

• Puede usar un pequeño truco para diferenciar la fila seleccionada de todas


las otras filas ... Tenga en cuenta que la propiedad Fila (entero) es igual a la
propiedad ActiveRecord (+1) del objeto DataLink que la fila seleccionada
está por pintarse .

• Nota: Es probable que desee deshabilitar este comportamiento (el


método MoveBy en el controlador de eventos OnMouseMove )
cuando DataSet conectado a un DBGrid está en modo Edición o Insertar .
Cómo seleccionar MultiSelect en Delphi
DBGrid
• by Zarko Gajic

El DBGrid de Delphi es uno de los componentes más conocidos de DB en


aplicaciones relacionadas con bases de datos. Su objetivo principal es permitir que
los usuarios de su aplicación manipulen los registros de un conjunto de datos en
una cuadrícula tabular.

Una de las características menos conocidas del componente DBGrid es que se


puede configurar para permitir la selección de múltiples filas. Lo que esto significa
es que sus usuarios pueden tener la capacidad de seleccionar múltiples registros
(filas) del conjunto de datos conectado a la red.

Permitir selecciones múltiples

Para habilitar la selección múltiple, solo necesita establecer el


elemento dgMultiSelect en "Verdadero" en la propiedad Opciones .
Cuando dgMultiSelect es "Verdadero", los usuarios pueden seleccionar múltiples
filas en una grilla usando las siguientes técnicas:

▪ Ctrl + clic del mouse


▪ Shift + teclas de flecha
Las filas / registros seleccionados se representan como marcadores y se
almacenan en la propiedad SelectedRows de la cuadrícula.

Tenga en cuenta que SelectedRows solo es útil cuando la propiedad Options se


establece en "True" para dgMultiSelect y dgRowSelect . Por otro lado, al
usar dgRowSelect (cuando no se pueden seleccionar celdas individuales), el
usuario no podrá editar registros directamente a través de la grilla y, y dgEditing se
configurará automáticamente en "False".

La propiedad SelectedRows es un objeto de tipo TBookmarkList . Podemos usar la


propiedad SelectedRows para, por ejemplo:

▪ Obtenga la cantidad de filas seleccionadas


▪ Borrar la selección (deseleccionar)
▪ Eliminar todos los registros seleccionados

▪ Verifique si se seleccionó un registro en particular


Para establecer dgMultiSelect en "Verdadero", puede usar el Inspector de
Objetos en tiempo de diseño o usar un comando como este en tiempo de
ejecución:

DBGrid1.Options: = DBGrid1.Options + [dgMultiSelect];

dgMultiSelect Ejemplo

Una buena situación para usar dgMultiSelect podría ser cuando necesite una
opción para seleccionar registros aleatorios o si necesita la suma de los valores de
los campos seleccionados.

El siguiente ejemplo utiliza componentes ADO ( AdoQuery conectado


a ADOConnection y DBGrid conectado a AdoQuery sobre DataSource ) para
visualizar los registros de una tabla de base de datos en un componente DBGrid.

El código usa selección múltiple para obtener la suma de los valores en el campo
"Tamaño". Utilice este código de ejemplo si desea seleccionar todo el DBGrid :

procedimiento TForm1.btnDoSumClick (Sender: TObject); var i: entero; suma:


Individual; comience si DBGrid1.SelectedRows.Count> 0 luego begin sum: =
0; con DBGrid1.DataSource.DataSet do begin for i: =
0 to DBGrid1.SelectedRows.Count-1 comenzar GotoBookmark (Puntero
(DBGrid1.SelectedRows.Items [i])); sum: = suma + AdoQuery1.FieldByName
('Tamaño'). AsFloat; fin ; fin ; edSizeSum.Text: = FloatToStr (suma); extremo final ;

Cómo usar las casillas de verificación en


un DBGrid
• by Zarko Gajic
• Haga que su aplicación sea más atractiva visualmente

• Existen numerosas formas y razones para personalizar el resultado de


un DBGrid en Delphi . Una forma es agregar casillas de verificación para
que el resultado sea más atractivo visualmente.

• De forma predeterminada, si tiene un campo booleano en su conjunto de


datos, DBGrid los muestra como "Verdadero" o "Falso" dependiendo del
valor del campo de datos. Sin embargo, parece mucho mejor si elige usar
un control de casilla de verificación "verdadero" para habilitar la edición de
los campos.
• Crear una aplicación de muestra
• Inicie un nuevo formulario en Delphi y coloque un TDBGrid, TADOTable y
TDOConnection, TDataSource.

• Deje todos los nombres de los componentes tal como están cuando se
colocaron primero en el formulario (DBGrid1, ADOQuery1, AdoTable 1,
etc.). Utilice el Inspector de Objetos para establecer una propiedad
ConnectionString del componente ADOConnection1 (TDOConnection) para
que apunte a la base de datos de muestra QuickiesContest.mdb MS
Access.

• Conecte DBGrid1 a DataSource1, DataSource1 a ADOTable1, y finalmente


a ADOTable1 a ADOConnection1. La propiedad ADOTable1 TableName
debe señalar a la tabla Artículos (para hacer que DBGrid muestre los
registros de la tabla Artículos).

• Si ha establecido todas las propiedades correctamente, cuando ejecuta la


aplicación (dado que la propiedad Activo del componente ADOTable1 es
Verdadero) debería ver, de forma predeterminada, que el DBGrid muestra
el valor del campo booleano como "Verdadero" o "Falso" dependiendo en el
valor del campo de datos.

• CheckBox en una DBGrid


• Para mostrar una casilla de verificación dentro de una celda de un DBGrid,
necesitaremos tener uno disponible para nosotros en tiempo de ejecución.

• Seleccione la página "Controles de datos" en la Paleta de componentes y


elija un TDBCheckbox . Coloque uno en cualquier lugar del formulario, no
importa dónde, ya que la mayoría de las veces será invisible o flotante en la
cuadrícula.

• Consejo: TDBCheckBox es un control de datos que permite al usuario


seleccionar o anular la selección de un solo valor, que es apropiado para
los campos booleanos.

• A continuación, establezca su propiedad Visible en False. Cambie la


propiedad Color de DBCheckBox1 al mismo color que DBGrid (para que se
mezcle con DBGrid) y elimine el Título.

• Lo que es más importante, asegúrese de que DBCheckBox1 esté


conectado al DataSource1 y al campo correcto.

• Tenga en cuenta que todos los valores de propiedad de DBCheckBox1


anteriores se pueden establecer en el evento OnCreate del formulario como
este:
• procedure TForm1.FormCreate (Sender:
TObject); comenzar DBCheckBox1.DataSource: = DataSource1;
DBCheckBox1.DataField: = 'Ganador'; DBCheckBox1.Visible: = False;
DBCheckBox1.Color: = DBGrid1.Color; DBCheckBox1.Caption: = ''; // explicado más
adelante en el artículo DBCheckBox1.ValueChecked: = 'Yes a Winner!';
DBCheckBox1.ValueUnChecked: = 'No esta vez.'; fin ;

• Lo que viene a continuación es la parte más interesante. Mientras editamos


el campo booleano en DBGrid, necesitamos asegurarnos de que
DBCheckBox1 esté arriba ("flotante") de la celda en el DBGrid que muestra
el campo booleano.

• Para el resto de las celdas (no enfocadas) que llevan los campos booleanos
(en la columna "Ganador"), necesitamos proporcionar alguna
representación gráfica del valor booleano (Verdadero / Falso).

• Esto significa que necesita al menos dos imágenes para dibujar: una para el
estado comprobado (valor verdadero) y otra para el estado no verificado
(valor falso).

• La forma más sencilla de lograr esto es utilizar la función


DrawFrameControl de la API de Windows para dibujar directamente en el
lienzo de DBGrid.

• Aquí está el código en el controlador de eventos OnDrawColumnCell de


DBGrid que ocurre cuando la grilla necesita pintar una celda.

• procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect;


DataCol: Entero; Columna: TColumn; Estado:
TGridDrawState); const IsChecked: array [Boolean] de Integer =
(DFCS_BUTTONCHECK, DFCS_BUTTONCHECK o DFCS_CHECKED); var DrawState:
entero; DrawRect: TRect; comience if (gdFocused en State)
y luego comience if (Column.Field.FieldName = DBCheckBox1.DataField)
y luego comience DBCheckBox1.Left: = Rect.Left + DBGrid1.Left + 2;
DBCheckBox1.Top: = Rect.Top + DBGrid1.top + 2; DBCheckBox1.Width: =
Rect.Right - Rect.Left; DBCheckBox1.Height: = Rect.Bottom - Rect.Top;
DBCheckBox1.Visible: = Verdadero; end end else begin if (Column.Field.FieldName
= DBCheckBox1.DataField) luego comienza DrawRect: = Rect; InflateRect
(DrawRect, -1, -1); DrawState: = ISChecked [Column.Field.AsBoolean];
DBGrid1.Canvas.FillRect (Rect); DrawFrameControl (DBGrid1.Canvas.Handle,
DrawRect, DFC_BUTTON, DrawState); fin ; fin ; fin ;

• Para finalizar este paso, debemos asegurarnos de que DBCheckBox1 sea


invisible cuando salgamos de la celda:
• procedure TForm1.DBGrid1ColExit (Sender:
TObject); comience si DBGrid1.SelectedField.FieldName =
DBCheckBox1.DataField entonces DBCheckBox1.Visible: = False end ;

• Solo necesitamos dos eventos más para manejar.

• Tenga en cuenta que cuando se está en el modo de edición, todas las


pulsaciones de teclas van a la celda de DBGrid, debemos asegurarnos de
que se envíen al CheckBox. En el caso de un CheckBox, nos interesan
principalmente las teclas [Tab] y [Space]. [Tab] debería mover el foco de
entrada a la celda siguiente, y [Espacio] debería alternar el estado de
CheckBox.

• procedure TForm1.DBGrid1KeyPress (Sender: TObject; var Key:


Char); comience si (clave = Chr (9)) luego
Salga ; if (DBGrid1.SelectedField.FieldName =
DBCheckBox1.DataField) entonces comienza DBCheckBox1.SetFocus;
SendMessage (DBCheckBox1.Handle, WM_Char, palabra (clave), 0); fin ; fin ;

• Podría ser apropiado que el título de la casilla de verificación cambie a


medida que el usuario marca o desmarca la casilla. Tenga en cuenta que
DBCheckBox tiene dos propiedades (ValueChecked y ValueUnChecked)
utilizadas para especificar el valor de campo representado por la casilla de
verificación cuando está marcada o desmarcada.

• Esta propiedad ValueChecked contiene "Sí, un ganador!", Y


ValueUnChecked equivale a "No esta vez".

• procedimiento TForm1.DBCheckBox1Click (Sender:


TObject); comenzar si DBCheckBox1.Checked entonces DBCheckBox1.Caption: =
DBCheckBox1.ValueChecked else DBCheckBox1.Caption: =
DBCheckBox1.ValueUnChecked; fin;

• Ejecute el proyecto y verá las casillas de verificación en toda la columna del


campo Ganador.

Implementando el algoritmo de
clasificación QuickSort en Delphi
• by Zarko Gajic
• Uno de los problemas comunes en la programación es ordenar una matriz
de valores en algún orden (ascendente o descendente).
• Si bien hay muchos algoritmos de clasificación "estándar", QuickSort es uno
de los más rápidos. Quicksort ordena empleando una estrategia de divide y
vencerás para dividir una lista en dos sublistas.

• Algoritmo QuickSort
• El concepto básico es elegir uno de los elementos en la matriz,
llamado pivote . Alrededor del pivote, otros elementos serán reorganizados.

• Todo lo que no sea el pivote se mueve hacia la izquierda del pivote, hacia la
partición izquierda. Todo lo que sea mayor que el pivote entra en la
partición correcta. En este punto, cada partición es recursiva "ordenada
rápidamente".

• Aquí está el algoritmo QuickSort implementado en Delphi:

• > procedimiento QuickSort ( var A: array de Integer; iLo, iHi: Integer); var Lo, Hola,
Pivote, T: Entero; comenzar Lo: = iLo; Hola: = iHi; Pivote: = A [(Lo +
Hi) div 2]; repita mientras A [Lo] do Inc (Lo); mientras que A [Hi]> Pivot do Dec
(Hi); si Lo <= Hi entonces comienza T: = A [Lo]; A [Lo]: = A [Hola]; A [Hola]: = T; Inc
(Lo); Dec (Hola); fin ; hasta Lo> Hola; si Hola> iLo entonces QuickSort (A, iLo,
Hola); si Lo entonces QuickSort (A, Lo, iHi); fin ;

• Uso:

• > var intArray: array de entero; comenzar SetLength (intArray, 10); // Agregar
valores a intArray intArray [0]: = 2007; ... intArray [9]: = 1973; // ordenar QuickSort
(intArray, Low (intArray), High (intArray));

• Nota: en la práctica, QuickSort se vuelve muy lento cuando la matriz que se


le pasó ya está cerca de ser ordenada.

• Hay un programa de demostración que se envía con Delphi, llamado


"thrddemo" en la carpeta "Threads" que muestra dos algoritmos de
clasificación adicionales: Bubble sort y Selection Sort.

Formateo de los valores de fecha y hora


para acceder a SQL en Delphi
• by Zarko Gajic

¿Alguna vez ha recibido el horrible "El objeto del parámetro está


incorrectamente definido. Se ha proporcionado información incompleta o
incoherente " Error JET? He aquí cómo rectificar la situación.
Cuando necesite crear una consulta SQL en una base de datos de Access donde
se usa un valor de fecha (o fecha y hora), debe asegurarse de utilizar el formato
correcto.

Por ejemplo, en una consulta SQL: "SELECT * FROM TBL WHERE DateField =
'10 / 12/2008 '" desea obtener todos los registros de la tabla denominada TBL
donde un campo de fecha general DateField es igual a 10/12/2008.

¿Está clara la línea de arriba? ¿Es eso el 10 de diciembre o el 12 de octubre?


Afortunadamente, estamos bastante seguros de que el año en la consulta es
2008.

¿Debe especificarse la fecha de la consulta como MM / DD / AAAA o DD / MM /


AAAA o quizás AAAAMMDD? ¿Y la configuración regional juega un papel aquí?

MS Access, Jet, formato de fecha y hora

Al utilizar Access y JET ( controles dbGo - ADO Delphi ), el formato del SQL para
el campo de fecha debe * siempre * ser:

> # YYYY-MM-DD #
Cualquier otra cosa podría funcionar en pruebas limitadas pero a menudo puede
conducir a resultados inesperados o errores en la máquina del usuario.

Aquí hay una función Delphi personalizada que puede usar para formatear un
valor de fecha para la consulta de Access SQL.

> función DateForSQL ( const date: TDate): cadena ; var y, m, d:


palabra; comenzar DecodeDate (date, y, m, d); resultado: = Formato ('#%. * d -%. * d
-%. * d #', [4, y, 2, m, 2, d]); fin ;
Para "29 de enero de 1973" la función devolverá la cadena '# 1973-01-29 #'.

¿Acceder al formato de fecha y hora de SQL?

En cuanto al formato de fecha y hora, el formato general es:

> # aaaa-mm-dd HH: MM: SS #


Esto es: # year-month-daySPACEhour: minute: second #

Tan pronto como construya una cadena de fecha y hora válida para el SQL
usando el formato general anterior y lo intente usando cualquiera de los
componentes del conjunto de datos de Delphi como TADOQuery, recibirá el
horrible "El objeto del parámetro está definido incorrectamente. Se proporcionó
información incompleta o incoherente" en tiempo de ejecución !
El problema con el formato anterior está en el carácter ":", ya que se usa para
parámetros en consultas Delphi parametrizadas. Como en "... WHERE DateField
=: dateValue" - aquí "dateValue" es un parámetro y ":" se usa para marcarlo.

Una forma de "corregir" el error es usar otro formato para fecha / hora (reemplace
":" por "."):

> # aaaa-mm-dd HH.MM.SS #


Y aquí está una función Delphi personalizada para devolver una cadena de un
valor de fecha y hora que puede usar al construir consultas SQL para Access
donde necesita buscar un valor de fecha y hora:

> función DateTimeForSQL ( const dateTime: TDateTime): cadena ; var y, m, d:


palabra; hora, min, sec, mseg: palabra; comenzar DecodeDate (dateTime, y, m,
d); DecodeTime (dateTime, hour, min, sec, msec); resultado: = Formato ('#%. * d -%. *
d -%. * d%. * d.%. * d.%. * d #', [4, y, 2, m, 2, d, 2, hora, 2, min, 2, sec]); fin ;
¡El formato se ve raro pero dará como resultado el valor de la cadena de fecha y
hora correctamente formateado para ser utilizado en consultas SQL!

Aquí hay una versión más corta que usa la rutina FormatDateTime:

> función DateTimeForSQL ( const dateTime: TDateTime): cadena ; begin result: =


FormatDateTime ('# aaaa-mm-dd hh.nn.ss #', dateTime); fin ;

Comunicación entre formularios


• by Zarko Gajic
• Averiguar cómo se cerró un formulario modal
• Los formularios modales ofrecen características específicas que no
podemos tener cuando se muestran de forma no modal. Más comúnmente,
mostraremos un formulario de manera modal para aislar sus procesos de
cualquier cosa que de otro modo podría ocurrir en el formulario principal.
Una vez que se completen estos procesos, es posible que desee saber si el
usuario presionó el botón Guardar o Cancelar para cerrar el formulario
modal. Puede escribir un código interesante para lograr esto, pero no tiene
por qué ser difícil.
• Delphi proporciona formularios modales con la propiedad ModalResult, que
podemos leer para contar cómo el usuario salió del formulario.
• El siguiente código devuelve un resultado, pero la rutina de llamada lo
ignora:
var F: TForm2; begin F: = TForm2.Create ( nil ); F.ShowModal; F.Liberación; ...

• El ejemplo que se muestra arriba solo muestra el formulario, permite que el


usuario haga algo con él y luego lo libera. Para verificar cómo se terminó el
formulario, debemos aprovechar el hecho de que el método ShowModal es
una función que devuelve uno de varios valores de ModalResult. Cambiar la
linea
• F.ShowModal
• a
• si F.ShowModal = mrOk entonces
• Necesitamos algún código en la forma modal para configurar lo que sea
que queremos recuperar. Hay más de una forma de obtener ModalResult
porque TForm no es el único componente que tiene una propiedad
ModalResult; TButton también tiene uno.
• Echemos un vistazo a TButton's ModalResult primero. Comience un nuevo
proyecto y agregue un formulario adicional (menú principal Delphi IDE:
Archivo -> Nuevo -> Formulario).
• Esta nueva forma tendrá un nombre 'Form2'. A continuación, agregue un
TButton (Nombre: 'Button1') al formulario principal (Form1), haga doble clic
en el nuevo botón e ingrese el siguiente código:

procedure TForm1.Button1Click (Sender: TObject); var f: TForm2; begin f: = TForm2.Create ( nil ); intente si f.ShowM
mrOk luego Caption: = 'Yes' else Leyenda: = 'No'; finalmente f. Libera; fin ; fin ;

• Ahora selecciona el formulario adicional. Dale dos TButtons, etiquetando un


'Guardar' (Nombre: 'btnSave'; Leyenda: 'Guardar') y el otro 'Cancelar'
(Nombre: 'btnCancel'; Leyenda: 'Cancelar'). Seleccione el botón Guardar y
presione F4 para abrir el Inspector de objetos, desplácese hacia arriba /
abajo hasta que encuentre la propiedad ModalResult y configúrelo en mrOk.
Vuelva al formulario y seleccione el botón Cancelar, presione F4,
seleccione la propiedad ModalResult y configúrelo en mrCancel.
• Es tan simple como eso. Ahora presione F9 para ejecutar el proyecto.
(Según la configuración de su entorno, Delphi puede solicitarle que guarde
los archivos). Una vez que aparezca el formulario principal, presione el
Botón1 que agregó anteriormente para mostrar el formulario secundario.
Cuando aparezca el formulario secundario, presione el botón Guardar y el
formulario se cerrará, una vez que vuelva al formulario principal, tenga en
cuenta que su título dice "Sí". Presione el botón principal del formulario para
que aparezca nuevamente el formulario secundario, pero esta vez presione
el botón Cancelar (o el elemento Cerrar del menú Sistema o el botón [x] en
el área de título). El título de la forma principal leerá "No".
• ¿Como funciona esto? Para averiguar, eche un vistazo al evento Click para
TButton (desde StdCtrls.pas):

procedimiento TButton.Click; var Form: TCustomForm; begin Form: = GetParentForm (Self); si es nulo, entonces Fo
ModalResult; Click heredado ; fin ;

• Lo que sucede es que el Propietario (en este caso, la forma secundaria) de


TButton obtiene su ModalResult establecido de acuerdo con el valor del
TButton's ModalResult. Si no establece TButton.ModalResult, entonces el
valor es mrNone (de forma predeterminada). Incluso si el TButton se coloca
en otro control, la forma principal se sigue utilizando para establecer su
resultado. La última línea invoca el evento Click heredado de su clase
antecesora.
• Para comprender lo que sucede con Forms ModalResult vale la pena
revisar el código en Forms.pas, que debería poder encontrar en .. \ DelphiN
\ Source (donde N representa el número de versión).
• En la función ShowModal de TForm, justo después de que se muestra el
formulario, se inicia el bucle Repeat-Until, que sigue buscando que la
variable ModalResult se convierta en un valor mayor que cero. Cuando esto
ocurre, el código final cierra el formulario.
• Puede establecer ModalResult en tiempo de diseño, como se describe
anteriormente, pero también puede establecer la propiedad ModalResult del
formulario directamente en el código en tiempo de ejecución.

Determine su IP con Delphi


• by Zarko Gajic
• Internet esto e Internet que. Todo el mundo quiere estar en Internet hoy en
día. Todo el mundo quiere programar Internet hoy en día.

• Una de las tareas más interesantes al comenzar a codificar para Internet es


cómo obtener la dirección IP de una computadora conectada a Internet.

• IP? TCP?
• Simplemente técnico: Internet se basa en conexiones TCP / IP. La parte
TCP describe cómo dos computadoras establecen una conexión entre sí y
transfieren datos.

• Parte de IP trata principalmente de cómo obtener un mensaje enrutado a


través de Internet. Cada máquina conectada tiene una dirección IP única
que permite a los demás encontrar una ruta a cualquier computadora
alrededor de la WWW (o del mundo precisamente).
• Utiliza Winsock
• Para obtener la dirección IP de la computadora que está utilizando cuando
está conectado a Internet, debemos llamar a algunas de las funciones API *
definidas * en la unidad Winsock.

• Crearemos una función GetIPFromHost que invoque varias funciones de


Winsock API para obtener la IP. Antes de que podamos usar funciones de
WinSock, debemos tener una sesión válida. Esta sesión se crea con la
función WinSock WSAStartup. Al final de nuestra función, se realiza una
llamada al leanup de SAC para finalizar el uso de la API de Windows
Sockets. Para obtener la dirección IP de la computadora, debemos usar
GetHostByName junto con GetHostName. Cada computadora se llama host
y podemos obtener el nombre de host con una llamada de función especial:
GetHostName.

• Nosotros usamos GetHostByName para obtener la dirección IP relacionada


con este nombre de host.

• Obtener IP Delphi.Project.Code
• Inicie Delphi y coloque un botón y dos cuadros de edición en un formulario
recién creado. Agregue la función GetIPFromHost a la parte de
implementación de su unidad y asigne el siguiente código al controlador de
eventos OnClick de un botón (a continuación):

• usa Winsock; función GetIPFromHost ( var HostName, IPaddr, WSAErr: cadena ):


Boolean; escriba Name = array [0..100] de Char; PName = ^ Nombre; var HEnt:
pHostEnt; HName: PName; WSAData: TWSAData; i: Entero; comenzar Resultado: =
Falso; si WSAStartup ($ 0101, WSAData) 0 entonces comienza WSAErr: = 'Winsock
no responde.' '; Exit; end ; IPaddr: =' '; Nuevo (HName); si GetHostName (HName ^,
SizeOf (Name)) = 0 luego comience HostName: = StrPas (HName ^); HEnt: =
GetHostByName (HName ^); para i: = 0 a HEnt ^ .h_length - 1 do IPaddr: = Concat
(IPaddr, IntToStr (Ord (HEnt ^ .h_addr_list ^ [ i])) + '.'); SetLength (IPaddr, Length
(IPaddr) - 1); Result: = True; end else
begin case WSAGetLastError de WSANOTINITIALISED: WSAErr: =
'WSANotInialized'; WSAENETDOWN: WSAErr: = 'WSAENetDown' ;
WSAEINPROGRESS: WSAErr: = 'WSAEInProgress'; end ; end ; Dispose (HName);
WSACleanup; end ; procedimiento TForm1.Button1Click (Sender:
TObject); var Host, IP, Err: cadena ; comience si GetIPFromHost (Host, IP,
Err) luego comience Edit1.Text: = Host; Edit2.Text: = IP; end else MessageDlg (Err,
mtError, [mbOk], 0); end ;
Ejemplo Del Delphi Thread Pool Usando
AsyncCalls
• by Zarko Gajic
• Unidad AsyncCalls por Andreas Hausladen - ¡Usemos (y ampliémoslo)!

• Este es mi próximo proyecto de prueba para ver qué biblioteca de


subprocesos para Delphi me sería más adecuada para mi tarea de
"escaneo de archivos" que me gustaría procesar en múltiples subprocesos /
en un grupo de subprocesos.

• Para repetir mi objetivo: transformar mi "escaneo de archivos" secuencial


de 500-2000 + archivos desde el enfoque no enhebrado a uno enhebrado.
No debería tener 500 subprocesos ejecutándose a la vez, por lo tanto, me
gustaría usar un grupo de subprocesos. Un grupo de subprocesos es una
clase de cola que alimenta varios subprocesos en ejecución con la
siguiente tarea de la cola.

• El primer intento (muy básico) se realizó simplemente extendiendo la clase


TThread e implementando el método Execute (mi analizador de cadenas
enhebrado).

• Dado que Delphi no tiene una clase de grupo de subprocesos


implementada de la caja, en mi segundo intento he intentado utilizar
OmniThreadLibrary por Primoz Gabrijelcic.

• OTL es fantástico, tiene un montón de maneras de ejecutar una tarea en


segundo plano, un camino por recorrer si quieres tener un enfoque de
"disparar y olvidar" para ejecutar la ejecución de piezas de tu código.

• AsyncCalls por Andreas Hausladen


• > Nota: lo que sigue sería más fácil de seguir si primero descarga el código fuente.

• Mientras exploro más formas de ejecutar algunas de mis funciones de


manera enhebrada, decidí probar también la unidad "AsyncCalls.pas"
desarrollada por Andreas Hausladen. Andy's AsyncCalls - La unidad de
llamadas a función asíncrona es otra biblioteca que un desarrollador de
Delphi puede usar para aliviar el dolor de implementar un enfoque
enhebrado para ejecutar algún código.

• Desde el blog de Andy: con AsyncCalls puede ejecutar múltiples funciones


al mismo tiempo y sincronizarlas en cada punto de la función o método que
las inició. ... La unidad AsyncCalls ofrece una variedad de prototipos de
funciones para llamar a funciones asíncronas. ... ¡Implementa un grupo de
hilos! La instalación es súper fácil: solo use llamadas asíncronas desde
cualquiera de sus unidades y tendrá acceso instantáneo a cosas como
"ejecutar en un hilo separado, sincronizar la interfaz de usuario principal,
esperar hasta que finalice".

• Además de las AsyncCalls de uso gratuito (licencia MPL), Andy también


publica con frecuencia sus propias correcciones para Delphi IDE, como
"Delphi Speed Up" y "DDevExtensions", estoy seguro de que has oído
hablar (si no lo has hecho ya).

• AsyncCalls en acción
• Si bien solo hay una unidad para incluir en su aplicación, asynccalls.pas proporciona
más formas en que uno puede ejecutar una función en un hilo diferente y
sincronizar el hilo. Eche un vistazo al código fuente y al archivo de ayuda HTML
incluido para familiarizarse con los conceptos básicos de asynccalls.

• En esencia, todas las funciones de AsyncCall devuelven una interfaz


IAsyncCall que permite sincronizar las funciones. IAsnycCall expone los
siguientes métodos: >

• >>> // v 2.98 de asynccalls.pas IAsyncCall = interfaz // espera hasta que la función


finalice y devuelve la función de valor de retorno Sincronización: Entero; //
devuelve True cuando la función asíncrona está terminada Función Finalizado:
Booleano; // devuelve el valor de retorno de la función asincrónica, cuando Finished
es TRUE function ReturnValue: Integer; // le dice a AsyncCalls que la función
asignada no debe ejecutarse en el procedimiento de
amenaza actual ForceDifferentThread; fin; Como me gustan los métodos
genéricos y anónimos, me alegra que exista una clase TAsyncCalls que envuelva las
llamadas a mis funciones. Quiero que se ejecute de manera enhebrada.

• Aquí hay una llamada de ejemplo a un método que espera dos parámetros
enteros (devolviendo un IAsyncCall): >

• >>> TAsyncCalls.Invoke (AsyncMethod, i, Random (500)); El AsyncMethod es un


método de una instancia de clase (por ejemplo: un método público de un
formulario) y se implementa como: >>>> función TAsyncCallsForm.AsyncMethod
(taskNr, sleepTime: integer): entero; comenzar el resultado: = sleepTime; Dormir
(hora de dormir); TAsyncCalls.VCLInvoke ( procedimiento begin Log (Formato
('hecho> nr:% d / tareas:% d / dormido:% d', [tasknr, asyncHelper.TaskCount,
sleepTime])); end ); fin ; Nuevamente, estoy usando el procedimiento Sleep para
imitar cierta carga de trabajo a realizar en mi función ejecutada en un hilo
separado.

• TAsyncCalls.VCLInvoke es una forma de sincronizar con el hilo principal (el


hilo principal de la aplicación, la interfaz de usuario de la aplicación).
VCLInvoke vuelve inmediatamente. El método anónimo se ejecutará en el
hilo principal.
• También hay VCLSync que se devuelve cuando se llamaba al método
anónimo en el hilo principal.

• Grupo de subprocesos en AsyncCalls


• Como se explica en el documento de ejemplos / ayuda (AsyncCalls Internals -
Thread pool y waiting-queue): se agrega una solicitud de ejecución a la cola de
espera cuando se realiza una sincronización. la función se inicia ... Si ya se alcanzó el
número máximo de subprocesos, la solicitud permanece en la cola de espera. De lo
contrario, se agrega un nuevo subproceso al grupo de subprocesos.

• Volver a la tarea de "escaneo de archivos": al alimentar (en un ciclo for) la


llamada asincrónica del grupo de subprocesos con una serie de llamadas
TAsyncCalls.Invoke (), las tareas se agregarán al grupo interno y se
ejecutarán "cuando llegue el momento" ( cuando las llamadas agregadas
previamente han terminado).

• Espere todas IAsyncCalls para terminar


• Necesitaba una forma de ejecutar más de 2000 tareas (escanear 2000+ archivos)
usando TAsyncCalls.Invoke () llamadas y también para tener una forma de
"WaitAll".

• La función AsyncMultiSync definida en asnyccalls espera a que finalicen las


llamadas asíncronas (y otros controladores). Hay algunas
formas sobrecargadas de llamar a AsyncMultiSync, y esta es la más
simple: >

• >>> function AsyncMultiSync ( const List: array de IAsyncCall; WaitAll: Boolean =


True; Milisegundos: Cardinal = INFINITO): Cardinal; También hay una limitación:
Longitud (Lista) no debe exceder MAXIMUM_ASYNC_WAIT_OBJECTS (61
elementos). Tenga en cuenta que List es una matriz dinámica de interfaces
IAsyncCall para las cuales la función debe esperar.

• Si quiero que se implemente "wait all", necesito completar una matriz de


IAsyncCall y hacer AsyncMultiSync en segmentos de 61.

• Mi ayudante de AsnycCalls
• Para ayudarme a implementar el método WaitAll, he codificado una simple clase
TAsyncCallsHelper. TAsyncCallsHelper expone un procedimiento AddTask (const
call: IAsyncCall); y rellena una matriz interna de array de IAsyncCall. Esta es
una matriz bidimensional donde cada elemento contiene 61 elementos de
IAsyncCall.

• Aquí hay una parte de TAsyncCallsHelper: >


• >>> ADVERTENCIA: código parcial! (código completo disponible para
descargar) usa AsyncCalls; tipo TIAsyncCallArray = array
de IAsyncCall; TIAsyncCallArrays = array de TIAsyncCallArray; TAsyncCallsHelper
= clase private fTasks: TIAsyncCallArrays; Tareas de propiedades :
TIAsyncCallArrays lee fTasks; procedimiento público AddTask (llamada const :
IAsyncCall); procedimiento WaitAll; fin ; Y la pieza de la sección de
implementación: >>>> ADVERTENCIA: ¡código
parcial! procedimiento TAsyncCallsHelper.WaitAll; var i: entero; begin for i: = High
(Tareas) down to Low (Tareas) comienzan AsyncCalls.AsyncMultiSync (Tareas
[i]); fin ; fin ; Tenga en cuenta que Tareas [i] es una matriz de IAsyncCall.

• De esta forma puedo "esperar todo" en trozos de 61


(MAXIMUM_ASYNC_WAIT_OBJECTS), es decir, esperando arreglos de
IAsyncCall.

• Con lo anterior, mi código principal para alimentar el grupo de subprocesos


se ve así: >

• >>> procedure TAsyncCallsForm.btnAddTasksClick (Sender: TObject); const nrItems


= 200; var i: entero; comience asyncHelper.MaxThreads: = 2 *
System.CPUCount; ClearLog ('inicio'); para i: = 1 a
nrItems comienzan asyncHelper.AddTask (TAsyncCalls.Invoke (AsyncMethod, i,
Random (500))); fin ; Log ('all in'); // espere todo //asyncHelper.WaitAll; // o permite
cancelar todo lo que no se inició al hacer clic en el botón "Cancelar todo": mientras
que no asyncHelper.AllFinished haga Application.ProcessMessages; Log
('terminado'); fin ; Nuevamente, Log () y ClearLog () son dos funciones simples para
proporcionar retroalimentación visual en un control Memo.

• ¿Cancelalo todo? - Tienes que cambiar el AsyncCalls.pas :(


• Como tengo que realizar más de 2000 tareas, y la encuesta de hilos se ejecutará
hasta 2 * System.CPUCount threads: las tareas estarán esperando en la cola del
pool de la banda de rodadura para ejecutarse.

• También me gustaría tener una forma de "cancelar" las tareas que están en
el grupo, pero estoy esperando su ejecución.

• Lamentablemente, AsyncCalls.pas no proporciona una forma simple de


cancelar una tarea una vez que se ha agregado al grupo de subprocesos.
No hay IAsyncCall.Cancel o IAsyncCall.DontDoIfNotAlreadyExecuting o
IAsyncCall.NeverMindMe.

• Para que esto funcione tuve que cambiar AsyncCalls.pas intentando


alterarlo lo menos posible, de modo que cuando Andy lanza una nueva
versión solo tengo que agregar algunas líneas para que funcione mi idea de
"Cancelar tarea".
• Esto es lo que hice: agregué un "procedimiento Cancelar" a IAsyncCall. El
procedimiento Cancelar establece el campo "FCancelled" (agregado) que
se verifica cuando el grupo está por comenzar la ejecución de la tarea.
Necesitaba modificar ligeramente el IAsyncCall.Finished (para que los
informes de una llamada finalizaran incluso cuando se cancelaran) y el
procedimiento TAsyncCall.InternExecuteAsyncCall (para no ejecutar la
llamada si se había cancelado).

• Puede usar WinMerge para localizar fácilmente las diferencias entre


Asynccall.pas originales de Andy y mi versión modificada (incluida en la
descarga).

• Puede descargar el código fuente completo y explorar.

• Confesión
• He alterado el asynccalls.pas de una manera que se adapta a las necesidades
específicas de mi proyecto. Si no necesita implementar "CancelAll" o "WaitAll" de la
manera descrita anteriormente, asegúrese de usar siempre, y solo, la versión
original de asynccalls.pas tal como la lanzó Andreas. Espero, sin embargo, que
Andreas incluya mis cambios como funciones estándar, tal vez no soy el único
desarrollador que intenta usar AsyncCalls, pero me faltan algunos métodos útiles :)

• ¡DARSE CUENTA! :)
• Solo unos días después de escribir este artículo, Andreas lanzó una nueva versión
2.99 de AsyncCalls. La interfaz IAsyncCall ahora incluye tres métodos más: >>>> El
método CancelInvocation evita que se invoque AsyncCall. Si AsyncCall ya está
procesado, una llamada a CancelInvocation no tiene efecto y la función Cancelada
devolverá False ya que AsyncCall no se canceló. El método Cancelado devuelve True
si cancela la AsyncCall mediante CancelInvocation. El método Forget desvincula la
interfaz IAsyncCall de la AsyncCall interna. Esto significa que si la última referencia a
la interfaz IAsyncCall se ha ido, la llamada asincrónica se seguirá ejecutando. Los
métodos de la interfaz arrojarán una excepción si son llamados después de llamar a
Forget. La función asíncrona no debe invocar al hilo principal porque podría
ejecutarse después de que el RTTL.Sincronizar / Mecanismo de cola fuera cerrado por
el RTL, lo que puede causar un bloqueo muerto. Por lo tanto, no es necesario usar
mi versión alterada .

• Sin embargo, tenga en cuenta que aún puede beneficiarse de mi


AsyncCallsHelper si necesita esperar a que todas las llamadas asincrónicas
finalicen con "asyncHelper.WaitAll"; o si necesita "Cancelar todo".

Cómo declarar e inicializar matrices


constantes en Delphi
• by Zarko Gajic

Cómo trabajar con arrays constantes en Delphi

En Delphi, el versátil lenguaje de programación web, los arreglos permiten a un


desarrollador referirse a una serie de variables con el mismo nombre y usar un
número, un índice, para diferenciarlas.

En la mayoría de los escenarios, declara una matriz como una variable, lo que
permite que los elementos de la matriz se modifiquen en tiempo de ejecución.

Sin embargo, algunas veces necesita declarar una matriz constante, una matriz de
solo lectura. No puede cambiar el valor de una constante o una variable de solo
lectura.

Por lo tanto, al declarar una matriz constante , también debe inicializarla.

Ejemplo de declaración de tres matrices constantes


Este ejemplo de código declara e inicializa tres arrays constantes,
denominados Days , CursorMode y Items .

▪ Days es una matriz de cadenas de seis elementos. Days [1] devuelve la cadena Mon.
▪ CursorMode es una matriz de dos elementos , por lo cual la declaración CursorMode
[false] = crHourGlass y CursorMode = crSQLWait. Las constantes "cr *" se pueden usar
para cambiar el cursor de la pantalla actual.
▪ Items define una matriz de tres registros de TShopItem.
tipo TShopItem = registro Nombre: cadena; Precio: moneda; fin; const Days: array [0..6] de
string = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); CursorMode: array [boolean] de
TCursor = (crHourGlass, crSQLWait); Items: array [1..3] de TShopItem = ((Nombre: 'Clock';
Price: 20.99), (Nombre: 'Pencil'; Precio: 15.75), (Nombre: 'Board'; Precio: 42.96));
Intentar asignar un valor para un elemento en una matriz constante aumenta el
error de tiempo de compilación "No se puede asignar el lado izquierdo". Por
ejemplo, el siguiente código no se ejecuta correctamente:

> Artículos [1] .Name: = 'Ver'; // no compilará

Cómo analizar una cadena delimitada en


una lista de cadenas
• by Zarko Gajic
• Hay muchas veces en las que necesita dividir una cadena en una matriz de
cadenas mediante el uso de un carácter como separador. Por ejemplo, un
archivo CSV ("coma" separado) podría tener una línea como "Zarko; Gajic ;;
DelphiGuide" y desea que esta línea se analice en 4 líneas (cadenas)
"Zarko", "Gajic", "" ( cadena vacía) y "DelphiGuide" utilizando el carácter de
punto y coma ";" como delimitador

• Delphi proporciona varios métodos para analizar una cadena, pero puede
encontrar que ninguno hace exactamente lo que necesita.

• Por ejemplo, el método ExtractStrings RTL siempre utiliza caracteres de


comillas (simples o dobles) para los delimitadores. Otro enfoque es usar las
propiedades Delimiter y DelimitedText de la clase TStrings, pero
desafortunadamente, hay un error en la implementación (Delphi "interno")
donde el carácter de espacio siempre se usa como delimitador.

• La única solución para analizar una cadena delimitada es escribir su propio


método:

• ~~~~~~~~~~~~~~~~~~~~~~~~~
procedimiento ParseDelimited (const sl: TStrings; const value: string; const
delimiter: string);
var
dx: entero;
ns: cadena;
txt: cadena;
delta: entero;
empezar
delta: = Longitud (delimitador);
txt: = valor + delimitador;
sl.BeginUpdate;
sl.Clear;
tratar
mientras que Length (txt)> 0 do
empezar
dx: = Pos (delimitador, txt);
ns: = Copia (txt, 0, dx-1);
sl.Add (ns);
txt: = Copiar (txt, dx + delta, MaxInt);
fin;
finalmente
sl.EndUpdate;
fin;
fin;
~~~~~~~~~~~~~~~~~~~~~~~~~
• Uso (rellena Memo1):
ParseDelimited (Memo1.lines, 'Zarko; Gajic ;; DelphiGuide', ';')

• Navegador de consejos de Delphi:


» Descripción y uso de tipos de datos de matriz en Delphi
« Rutinas de manejo de cadenas - Programación Delphi

Rutinas de manejo de cadenas:


Programación Delphi
• by Zarko Gajic
• La función CompareText compara dos cadenas sin mayúsculas y
minúsculas.

• Declaración:
función CompareText ( const S1, S2: string ): entero ;

• Descripción:
Compara dos cadenas sin mayúsculas y minúsculas.

• La comparación NO distingue entre mayúsculas y minúsculas y no tiene en


cuenta la configuración regional de Windows. El valor entero de retorno es
menor que 0 si S1 es menor que S2, 0 si S1 es igual a S2, o mayor que 0 si
S1 es mayor que S2.

• Esta función es obsoleta, es decir, no debe usarse en un código nuevo;


existe solo para compatibilidad con versiones anteriores.

• Ejemplo:

• var s1, s2: cadena; i: entero; s1: = 'Delphi'; s2: = 'Programación'; i: = CompareTexto
(s1, s2); //yo

• Copiar función
• Devuelve una subcadena de una cadena o un segmento de una matriz
dinámica.

• Declaración:
función Copiar (S; índice, recuento: entero): cadena ;
función Copiar (S; índice, recuento: entero): matriz ;

• Descripción:
Devuelve una subcadena de una cadena o un segmento de una matriz
dinámica.
S es una expresión de una cadena o tipo de matriz dinámica. El índice y el
recuento son expresiones de tipo entero. Copiar devuelve una cadena que
contiene una cantidad específica de caracteres de una cadena o matriz
secundaria que contiene elementos de conteo comenzando en S [Índice].

• Si Index es mayor que la longitud de S, Copy devuelve una cadena de


longitud cero ("") o una matriz vacía.
Si Count especifica más caracteres o elementos de matriz que están
disponibles, solo se devuelven los caracteres o elementos de S [Índice] al
final de S.

• Para determinar el número de caracteres en la cadena, use la función


Longitud. Una forma conveniente de copiar todos los elementos de S del
índice inicial es usar MaxInt como Count.

• Ejemplo:

• var s: cadena; s: = 'DELPHI'; s: = Copia (s, 2,3); // s = 'ELP';

• Eliminar procedimiento
• Elimina una subcadena de una cadena.

• Declaración:
Procedimiento Delete ( var S: string ; Index, Count: Integer)

• Descripción:
Elimina los caracteres de Conteo de una cadena S, comenzando en Índice.
Delphi no modifica la cadena si el índice no es positivo o mayor que el
número de caracteres después del índice. Si Count es mayor que el resto
de los caracteres después del índice, el resto de la cadena se elimina.

• Ejemplo:

• var s: cadena; s: = 'DELPHI'; Eliminar (s, 3,1) // s = DEPHI;

• Función ExtractStrings
• Rellena una lista de cadenas con subcadenas analizadas desde una lista
delimitada.

• Declaración:
tipo TSysCharSet = conjunto de Char;
función ExtractStrings (Separadores, WhiteSpace: TSysCharSet;
Contenido: PChar; Cadenas: TStrings): Entero;

• Descripción:
Rellena una lista de cadenas con subcadenas analizadas desde una lista
delimitada.

• Los separadores son un conjunto de caracteres que se utilizan como


delimitadores, que separan las subcadenas, donde el carro regresa, los
caracteres de nueva línea y los caracteres de comillas (simples o dobles)
siempre se tratan como separadores. WhiteSpace es un conjunto de
caracteres que deben ignorarse al analizar Contenido si se producen al
comienzo de una cadena. El contenido es la cadena terminada en nulo para
analizar las subcadenas. Strings es una lista de cadenas a la que se
agregan todas las subcadenas analizadas desde el Contenido. La función
devuelve el número de cadenas añadidas al parámetro Strings.

• Ejemplo:

• // ejemplo 1 - requiere que TMemo se llame "Memo1" ExtractStrings ([';', ','], [''],
'sobre: delphi; pascal, programming', memo1.Lines); // daría como resultado 3
cadenas añadidas a la nota: // sobre: delphi // pascal // programación // ejemplo 2
ExtractStrings ([DateSeparator], [''], PChar (DateToStr (Now)), memo1.Lines); // daría
como resultado 3 cadenas: día mes y año de la fecha currnet // por ejemplo '06',
'25', '2003'

• Función LeftStr
• Devuelve una cadena que contiene un número específico de caracteres del
lado izquierdo de una cadena.

• Declaración:
función LeftStr ( const AString: AnsiString; const Count: Integer):
AnsiString; sobrecarga ; función LeftStr ( const AString:
WideString; const Count: Integer): WideString; sobrecarga ;

• Descripción:
Devuelve una cadena que contiene un número específico de caracteres del
lado izquierdo de una cadena.

• AString representa una expresión de cadena desde la cual se devuelven los


caracteres más a la izquierda. El recuento indica cuántos caracteres
devolver. Si es 0, se devuelve una cadena de longitud cero (""). Si es igual
o mayor que el número de caracteres en AString, se devuelve la cadena
completa.

• Ejemplo:

• var s: cadena; s: = 'SOBRE PROGRAMACIÓN DELPHI'; s: = LeftStr (s, 5); // s =


'ABOUT'

• Función de longitud
• Devuelve un número entero que contiene el número de caracteres en una
cadena o la cantidad de elementos en una matriz.
• Descripción:
longitud de la función (const S: cadena ): entero
longitud de la función (const S: array ): entero

• Declaración:
Devuelve un número entero que contiene el número de caracteres en una
cadena o la cantidad de elementos en una matriz.
Para una matriz, Length (S) siempre devuelve Ord (High (S)) - Ord (Low
(S)) + 1

• Ejemplo:

• var s: cadena; i: entero; s: = 'DELPHI'; i: = longitud (es); // i = 6;

• Función LowerCase
• Devuelve una cadena que se ha convertido a minúsculas.

• Descripción:
función LowerCase ( const S: string ): cadena ;

• Declaración:
Devuelve una cadena que se ha convertido a minúsculas.
LowerCase solo convierte letras mayúsculas a minúsculas; todas las letras
minúsculas y los caracteres que no son letras permanecen sin cambios.

• Ejemplo:

• var s: cadena; s: = 'DeLpHi'; s: = LowerCase (s); // s = 'delphi';

• Pos función
• Devuelve un entero que especifica la posición de la primera aparición de
una cadena dentro de otra.

• Declaración:
función Pos (Str, Fuente: cadena ): entero ;

• Descripción:
Devuelve un entero que especifica la posición de la primera aparición de
una cadena dentro de otra.

• Pos busca la primera ocurrencia completa de Str en Fuente.

• Si encuentra uno, devuelve la posición del carácter en Origen del primer


carácter en Str como un valor entero; de lo contrario, devuelve 0.
Pos es sensible a las mayúsculas.

• Ejemplo:
• var s: cadena; i: entero; s: = 'PROGRAMACIÓN DELPHI'; i: = Pos ('HI PR', s); // i = 5;

• Función PosEx
• Devuelve un número entero que especifica la posición de la primera
aparición de una cadena dentro de otra, donde la búsqueda comienza en
una posición específica.

• Declaración:
función PosEx (Str, Fuente: cadena , StartFrom: cardinal = 1): entero ;

• Descripción:
Devuelve un número entero que especifica la posición de la primera
aparición de una cadena dentro de otra, donde la búsqueda comienza en
una posición específica.

• PosEx busca la primera aparición completa de Str en Source, comenzando


la búsqueda en StartFrom. Si encuentra uno, devuelve la posición del
carácter en Fuente del primer carácter en Str como un valor entero, de lo
contrario, devuelve 0. PosEx también devuelve 0 si StartFrom es mayor que
Length (Source) o si StartPos es <0

• Ejemplo:

• var s: cadena; i: entero; s: = 'PROGRAMACIÓN DELPHI'; i: = PosEx ('HI PR', s, 4); // i


= 1;

• Función QuotedStr
• Devuelve la versión entrecomillada de una cadena.

• Declaración:
función QuotedStr ( const S: cadena ): cadena ;

• Descripción:
Devuelve la versión entrecomillada de una cadena.

• Se inserta un carácter de comilla simple (') al principio y al final de la


cadena S, y se repite cada carácter de comilla simple en la cadena.

• Ejemplo:

var s: cadena; s: = 'Pascal' de Delphi; // ShowMessage devuelve Pascal s de Delphi: = QuotedStr (s); // ShowMessage
de Delphi
• Función ReverseString
• Devuelve una cadena en la que se invierte el orden de los caracteres de
una cadena especificada.

• Declaración:
función ReverseString ( const AString: string ): cadena ;

• Descripción: devuelve una cadena en la que se invierte el orden de los


caracteres de una cadena especificada

• Ejemplo:

• var s: cadena; s: = 'SOBRE PROGRAMACIÓN DELPHI'; s: = ReverseString (s); // s =


'GNIMMARGORP IHPLED TUOBA'

• Función RightStr
• Devuelve una cadena que contiene un número específico de caracteres del
lado derecho de una cadena.

• Declaración:
función RightStr ( const AString: AnsiString; const Count: Integer):
AnsiString; sobrecarga ;
función RightStr ( const AString: WideString; const Count: Integer):
WideString; sobrecarga ;

• Descripción:
Devuelve una cadena que contiene un número específico de caracteres del
lado derecho de una cadena.

• AString representa una expresión de cadena desde la cual se devuelven los


caracteres más a la derecha. El recuento indica cuántos caracteres
devolver. Si es igual o mayor que el número de caracteres en AString, se
devuelve la cadena completa.

• Ejemplo:

• var s: cadena; s: = 'SOBRE PROGRAMACIÓN DELPHI'; s: = RightStr (s, 5); // s =


'MMING'

• Función StringReplace
• Devuelve una cadena en la cual una subcadena especificada ha sido
reemplazada por otra subcadena.

• Declaración:
tipo TReplaceFlags = conjunto de (rfReplaceAll, rfIgnoreCase);

• función StringReplace ( const S, OldStr, NewStr: cadena ; Indicadores:


TReplaceFlags): cadena ;
• Descripción:
Devuelve una cadena en la cual una subcadena especificada ha sido
reemplazada por otra subcadena.

• Si el parámetro Flags no incluye rfReplaceAll, solo se reemplaza la primera


aparición de OldStr en S. De lo contrario, todas las instancias de OldStr se
reemplazan por NewStr.
Si el parámetro Flags incluye rfIgnoreCase, la operación de comparación no
distingue entre mayúsculas y minúsculas.

• Ejemplo:

• var s: cadena; s: = 'Los programadores de VB adoran el sitio de programación de


VB'; s: = ReplaceStr (s, 'VB', 'Delphi', [rfReplaceAll]); // s = 'Los programadores de
Delphi adoran el sitio de programación de Delphi';

• Función de ajuste
• Devuelve una cadena que contiene una copia de una cadena especificada
sin espacios iniciales y finales y caracteres de control.

• Declaración: función Trim ( const S: string ): cadena ;

• Descripción: devuelve una cadena que contiene una copia de una cadena
especificada sin espacios iniciales y finales y caracteres de control que no
son de impresión.

• Ejemplo:

• var s: cadena; s: = 'Delphi'; s: = Trim (s); // s = 'Delphi';

• Función UpperCase
• Devuelve una cadena que se ha convertido a mayúsculas.

• Declaración: función UpperCase ( const S: string ): cadena ;

• Descripción: devuelve una cadena que se ha convertido a mayúscula.


UpperCase solo convierte letras minúsculas a mayúsculas; todas las letras
mayúsculas y los caracteres que no son letras permanecen sin cambios.

• Ejemplo:

• var s: cadena; s: = 'DeLpHi'; s: = UpperCase (s); // s = 'DELPHI';

• Procedimiento Val
• Convierte una cadena en un valor numérico.

• Declaración: procedimiento Val ( const S: string ; var Result; var Code:


integer);
• Descripción:
Convierte una cadena en un valor numérico.

• S es una expresión de tipo cadena; debe ser una secuencia de caracteres


que forman un número real firmado. El argumento resultado puede ser un
entero o una variable de coma flotante. El código es cero si la conversión es
exitosa. Si la cadena no es válida, el índice del carácter ofensivo se
almacena en Código.

• Val no tiene en cuenta la configuración local para el separador decimal.

• Ejemplo:

• var s: cadena; c, i: entero; s: = '1234'; Val (s, i, c); // i = 1234; // c = 0

Leer y escribir números binarios


• by Angela Bradley
• El binario es un lenguaje que las computadoras entienden

• Cuando aprende la mayoría de los tipos de programación informática , toca


el tema de los números binarios. El sistema de números binarios juega un
papel importante en la forma en que se almacena la información en las
computadoras porque las computadoras solo entienden los números,
específicamente los números de la base 2. El sistema de números binarios
es un sistema de base 2 que usa solo los números 0 y 1 para representar
el encendido y apagado del sistema eléctrico de una computadora. Los
dos dígitos binarios, 0 y 1, se usan en combinación para comunicar
instrucciones de texto y del procesador de la computadora .

• Aunque el concepto de números binarios es simple una vez que se explica,


leer y escribirlos no está claro al principio. Para comprender los números
binarios, que utilizan un sistema de base 2, primero observe nuestro
sistema familiar de números de base 10.

• Sistema numérico de base 10: Matemáticas tal como lo conocemos


• Tome el número de tres dígitos 345 por ejemplo. El número más alejado a
la derecha, 5, representa la columna 1s, y hay 5 unidades. El siguiente
número de la derecha, el 4, representa la columna de 10s. Interpretamos el
número 4 en la columna de 10 como 40. La tercera columna, que contiene
el 3, representa la columna de 100, y sabemos que es de trescientos. En la
base 10, no nos tomamos el tiempo para pensar en esta lógica en cada
número. Lo sabemos por nuestra educación y años de exposición a los
números.
• Sistema de número de base 2: números binarios
• Binary funciona de manera similar. Cada columna representa un valor, y
cuando llena una columna, pasa a la siguiente columna.

• En nuestro sistema base 10, cada columna necesita llegar a 10 antes de


pasar a la siguiente columna. Cualquier columna puede tener un valor de 0
a 9, pero una vez que el conteo va más allá, agregamos una columna. En la
base dos, cada columna puede contener solo 0 o 1 antes de pasar a la
siguiente columna.

• En la base 2, cada columna representa un valor que es el doble del valor


anterior.

• Los valores de las posiciones, empezando por la derecha, son 1, 2, 4, 8, 16,


32, 64, 128, 256, 512, etc.

• El número uno se representa como 1 tanto en la base diez como en el


binario, así que pasemos al número dos. En la base diez, se representa con
un 2. Sin embargo, en binario, solo puede haber un 0 o un 1 antes de pasar
a la siguiente columna. Como resultado, el número 2 se escribe como 10 en
binario. Requiere un 1 en la columna 2s y 0 en la columna 1s.

• Echa un vistazo al número tres. Obviamente, en la base diez se escribe


como 3. En la base dos, se escribe como 11, lo que indica un 1 en la
columna 2s y un 1 en la columna 1s. 2 + 1 = 3.

• Lectura de números binarios


• Cuando sabes cómo funciona el binario, leerlo es simplemente una cuestión
de matemática simple. Por ejemplo:

• 1001 - Dado que conocemos el valor 'representa cada uno de estos


espacios, entonces sabemos que este número representa 8 + 0 + 0 + 1. En
la base diez, este sería el número 9.

• 11011 - Calcula qué es esto en base diez agregando los valores de cada
posición. En este caso, son 16 + 8 + 0 + 2 + 1. Este es el número 27 en la
base 10.

• Binarios en el trabajo en una computadora


• Entonces, ¿qué significa todo esto para la computadora? La computadora
interpreta combinaciones de números binarios como texto o instrucciones.

• Por ejemplo, a cada letra minúscula y mayúscula del alfabeto se le asigna


un código binario diferente. A cada uno también se le asigna una
representación decimal de ese código, llamado código ASCII . Por ejemplo,
a la "a" minúscula se le asigna el número binario 01100001. También está
representado por el código ASCII 097. Si hace los cálculos en el binario,
verá que es igual a 97 en la base 10.

Comprender las constantes tipadas en


Delphi
• by Zarko Gajic
• Cómo implementar valores persistentes entre llamadas a funciones.

• Cuando Delphi invoca un controlador de eventos, los antiguos valores de


las variables locales se anulan. ¿Qué pasa si queremos hacer un
seguimiento de cuántas veces se ha hecho clic en un botón? Podríamos
mantener los valores usando una variable de nivel de unidad, pero
generalmente es una buena idea reservar variables de nivel de unidad solo
para compartir información. Lo que necesitamos se suele llamar variables
estáticas o constantes tipadas en Delphi.

• ¿Variable o constante?
• Las constantes tipadas se pueden comparar con variables inicializadas: variables
cuyos valores se definen al ingresar a su bloque (generalmente controlador de
eventos). Dicha variable se inicializa solo cuando el programa comienza a
ejecutarse. Después de eso, el valor de una constante tipeada persiste entre
llamadas sucesivas a sus procedimientos.

• El uso de constantes tipadas es una forma muy limpia de implementar


variables inicializadas automáticamente. Para implementar estas variables
sin constantes tipadas, necesitaremos crear una sección de inicialización
que establezca el valor de cada variable inicializada.

• Constantes de tipo variable


• Aunque declaramos constantes tipadas en la sección const de un procedimiento, es
importante recordar que no son constantes. En cualquier punto de su aplicación, si
tiene acceso al identificador de una constante tipeada, podrá modificar su valor.

• Para ver las constantes escritas en el trabajo, coloque un botón en un


formulario en blanco y asigne el siguiente código al controlador de eventos
OnClick:

• > procedure TForm1.Button1Click (Sender: TObject); clics const : entero = 1; // no es


una constante verdadera begin Form1.Caption: = IntToStr (clicks); clics: = clics +
1; fin ; Tenga en cuenta que cada vez que hace clic en el botón, forma incrementos
de leyendas constantemente.
Ahora intente con el siguiente código: > procedure TForm1.Button1Click (Sender:
TObject); var clics: Entero; comenzar Form1.Caption: = IntToStr (clics); clics: = clics +
1; fin ; Ahora estamos usando una variable no inicializada para el contador de clics.
Observe ese valor extraño en el título de formularios después de hacer clic en el
botón.

• Constantes tipadas constantes


• Debes aceptar que la idea de las constantes modificables suena un poco extraña.
En versiones de 32 bits de Delphi Borland decidió desalentar su uso, pero los
admite para el código heredado Delphi 1.

• Podemos habilitar o deshabilitar las constantes tipeadas asignables en la


página del compilador del cuadro de diálogo Opciones del proyecto.

• Si ha desactivado las constantes tipeables asignables para un proyecto


determinado, cuando intente compilar el código anterior, Delphi le dará el
error "No se puede asignar el lado izquierdo" en la compilación. Sin
embargo, puede crear una constante tipada asignable declarando:

• > {$ J +} clics const : Entero = 1; {$ J-} Por lo tanto, el primer código de ejemplo se
ve así: > procedure TForm1.Button1Click (Sender: TObject); const {$ J +} clics: Entero
= 1; // no es una constante verdadera {$ J-} begin Form1.Caption: = IntToStr
(clicks); clics: = clics + 1; fin ;

• Conclusión
• Depende de usted decidir si desea que las constantes mecanografiadas sean
asignables o no. Lo importante aquí es que además de ser ideal para contadores,
las constantes tipadas son ideales para hacer que los componentes sean
alternativamente visibles o invisibles, o podemos usarlos para alternar entre
cualquier propiedad booleana. Las constantes tipadas también se pueden usar
dentro del controlador de eventos de TTimer para realizar un seguimiento de
cuántas veces se ha disparado.
Si desea más material para principiantes, consulte el resto de los temas de
programación de Delphi For Beginners.

Interfaces en la Programación Delphi 101


• by Zarko Gajic
• ¿Qué es una interfaz? Definiendo una interfaz. Implementando una interfaz.

• En Delphi, la palabra clave "interfaz" tiene dos significados distintos.

• En la jerga OOP, puede pensar en una interfaz como una clase sin
implementación .

• En la sección de interfaz de definición de unidades de Delphi se utiliza para


declarar cualquier sección de código público que aparezca en una unidad.
• Este artículo explicará las interfaces desde una perspectiva de OOP .

• Si desea crear una aplicación sólida como una roca para que su código sea
sostenible, reutilizable y flexible, la naturaleza OOP de Delphi lo ayudará a
conducir el primer 70% de su ruta.

• Definir interfaces e implementarlas ayudará con el 30% restante.

• Interfaces como clases abstractas


• Puede pensar en una interfaz como una clase abstracta con toda la
implementación eliminada y todo lo que no es público eliminado.

• Una clase abstracta en Delphi es una clase que no se puede instanciar: no


se puede crear un objeto de una clase marcada como abstracta.

• Echemos un vistazo a una declaración de interfaz de ejemplo:

• tipo
IConfigChanged = interface ['{0D57624C-CDDE-458B-A36C-436AE465B477}']
procedimiento ApplyConfigChange;
fin ;

• IConfigChanged es una interfaz. Una interfaz se define como una clase, se


usa la palabra clave "interfaz" en lugar de "clase".

• El compilador usa el valor Guid que sigue a la palabra clave de la interfaz


para identificar de forma única la interfaz. Para generar un nuevo valor
GUID, simplemente presione Ctrl + Shift + G en Delphi IDE. Cada interfaz
que defina necesita un valor Guid único.

• Una interfaz en OOP define una abstracción, una plantilla para una clase
real que implementará la interfaz, que implementará los métodos definidos
por la interfaz.

• Una interfaz en realidad no hace nada, solo tiene una firma para interactuar
con otras clases o interfaces (de implementación).

• La implementación de los métodos (funciones, procedimientos y propiedad


Obtener / Establecer métodos) se realiza en la clase que implementa la
interfaz.

• En la definición de interfaz no hay secciones de ámbito (privado, público,


publicado, etc.) todo es público . Un tipo de interfaz puede definir
funciones, procedimientos (que eventualmente se convertirán en métodos
de la clase que implementa la interfaz) y propiedades. Cuando una interfaz
define una propiedad, debe definir los métodos get / set: las interfaces no
pueden definir variables.
• Al igual que con las clases, una interfaz puede heredar de otras interfaces.

• tipo
IConfigChangedMore = interfaz (IConfigChanged)
procedimiento ApplyMoreChanges;
fin ;

• Las interfaces NO están COM SÓLO relacionadas


• La mayoría de los desarrolladores de Delphi cuando piensan en interfaces
piensan en la programación de COM. Sin embargo, las interfaces son solo
una característica de OOP del lenguaje, no están vinculadas
específicamente a COM.

• Las interfaces se pueden definir e implementar en una aplicación Delphi sin


tocar COM en absoluto.

• Implementando una interfaz


• Para implementar una interfaz, debe agregar el nombre de la interfaz a la
declaración de clase, como en:

• tipo
TMainForm = clase (TForm, IConfigChanged)
público
procedimiento ApplyConfigChange;
fin ;

• En el código anterior, una forma Delphi llamada "MainForm" implementa la


interfaz IConfigChanged.

• Advertencia : cuando una clase implementa una interfaz, debe implementar todos
sus métodos y propiedades. Si falla / olvida implementar un método (por ejemplo:
ApplyConfigChange) se producirá un error de tiempo de compilación "E2003
Identificador no declarado: 'ApplyConfigChange'" .

• Advertencia : si intenta especificar la interfaz sin el valor GUID,


recibirá: "Tipo E2086 'IConfigChanged' aún no está completamente
definido" .
• Cuándo usar una interfaz? Un ejemplo del mundo real. Finalmente :)
• Tengo una aplicación (MDI) donde se pueden mostrar varios formularios al
usuario a la vez. Cuando el usuario cambia la configuración de la
aplicación, la mayoría de los formularios necesitan actualizar su pantalla:
mostrar / ocultar algunos botones, actualizar los títulos de las etiquetas, etc.

• Necesitaba una forma simple de notificar a todos los formularios abiertos


que ha ocurrido un cambio en la configuración de la aplicación.
• La herramienta ideal para el trabajo fue una interfaz.

• Cada formulario que necesita actualizarse cuando la configuración cambia


implementará IConfigChanged.

• Como la pantalla de configuración se muestra modalmente, cuando se


cierra, el siguiente código garantiza que se notifique a todos los formularios
de implementación IConfigChanged y se llame a ApplyConfigChange:

• procedimiento DoConfigChange ();


var
cnt: entero;
icc: IConfigChanged;
empezar
para cnt: = 0 a -1 + Screen.FormCount do
empezar
if Admite (Screen.Forms [cnt], IConfigChanged, icc) luego
icc.ApplyConfigChange;
fin ;
fin ;

• La función de Soporte (definida en Sysutils.pas) indica si un objeto o


interfaz dado admite una interfaz específica.

• El código itera a través de la colección Screen.Forms (del objeto TScreen):


todos los formularios que se muestran actualmente en la aplicación.
Si un formulario Screen.Forms [cnt] admite la interfaz, Support devuelve la
interfaz para el último parámetro del parámetro y devuelve verdadero.

• Por lo tanto, si el formulario implementa el IConfigChanged, la variable icc


se puede usar para llamar a los métodos de la interfaz implementados por
el formulario.

• Tenga en cuenta, por supuesto, que cada formulario puede tener su propia
implementación diferente del procedimiento ApplyConfigChange .

• IUnknown, IInterface, TInterfacedObject, QueryInterface, _AddRef,


_Release
• Trataré de hacer que las cosas difíciles sean simples aquí :)

• Cualquier clase que definas en Delphi necesita tener un ancestro. TObject


es el máximo antecesor de todos los objetos y componentes.

• La idea anterior también se aplica a las interfaces, la IInterface es la clase


base para todas las interfaces.
• IInterface define 3 métodos: QueryInterface, _AddRef y _Release.

• Esto significa que nuestro IConfigChanged también tiene esos 3 métodos,


pero no los hemos implementado. Este es el por qué:

• TForm hereda de TComponent que ya implementa el IInterface por usted.

• Cuando desee implementar una interfaz en una clase que hereda de


TObject, asegúrese de que su clase hereda de TInterfacedObject en su
lugar. Dado que TInterfacedObject es un TObject que implementa
IInterface. Por ejemplo:

• TMyClass = clase ( TInterfacedObject , IConfigChanged)


procedimiento ApplyConfigChange;
fin ;

• Para finalizar este lío: IUnknown = IInterface. IUnknown es para COM.

Comprender y usar tipos de datos de


registro en Delphi
• by Zarko Gajic
• Los conjuntos están bien, las matrices son geniales.

• Supongamos que queremos crear tres matrices unidimensionales para 50


miembros en nuestra comunidad de programación. La primera matriz es
para nombres, la segunda para correos electrónicos y la tercera para la
cantidad de cargas (componentes o aplicaciones) a nuestra comunidad.

• Cada matriz (lista) tendría índices coincidentes y un montón de código para


mantener las tres listas en paralelo. Por supuesto, podríamos intentar con
una matriz tridimensional, pero ¿qué pasa con su tipo?

• Necesitamos cadenas para nombres y correos electrónicos, pero un


número entero para la cantidad de cargas.

• La forma de trabajar con dicha estructura de datos es utilizar la estructura


de registro de Delphi.

• TMember = grabar ...


• Por ejemplo, la siguiente declaración crea un tipo de registro llamado
TMember, el que podríamos usar en nuestro caso.

• > escriba TMember = registro Nombre: cadena ; Correo


electrónico: cadena ; Publicaciones: Cardenal; fin ;
• Esencialmente, una estructura de datos de registro puede mezclar
cualquiera de los tipos integrados de Delphi, incluidos los tipos que haya
creado. Los tipos de registro definen colecciones fijas de elementos de
diferentes tipos. Cada elemento, o campo , es como una variable, que
consiste en un nombre y un tipo.

• TMember type contiene tres campos: un valor de cadena llamado Name


(para mantener el nombre de un miembro), un valor de un tipo de cadena
llamado eMail (para un correo electrónico) y un entero (Cardinal) llamado
Posts (para contener el número de presentaciones a nuestra comunidad).

• Una vez que hemos configurado el tipo de registro, podemos declarar que
una variable es del tipo TMember.

• TMember ahora es tan bueno como el tipo de variable para variables como
cualquiera de los tipos integrados de Delphi, como String o Integer. Nota: la
declaración del tipo TMember no asigna ninguna memoria para los campos
Nombre, Correo electrónico y Publicaciones;

• Para crear realmente una instancia del registro TMember, debemos


declarar una variable del tipo TMember, como en el siguiente código:

• > var DelphiGuide, AMember: TMember;

• Ahora, cuando tenemos un registro, usamos un punto para aislar los


campos de DelphiGuide:

• > DelphiGuide.Name: = 'Zarko Gajic'; DelphiGuide.eMail: =


'delphi@aboutguide.com'; DelphiGuide.Posts: = 15;

• Nota: el fragmento de código anterior podría reescribirse con el uso de


la palabra clave :

• > con DelphiGuide do begin Nombre: = 'Zarko Gajic'; eMail: =


'delphi@aboutguide.com'; Publicaciones: = 15; fin ;

• Ahora podemos copiar los valores de los campos de DelphiGuide en


AMember:

• > AMember: = DelphiGuide;

• Registro de alcance y visibilidad


• El tipo de registro declarado dentro de la declaración de un formulario
(sección de implementación), función o procedimiento tiene un alcance
limitado al bloque en el que se declara. Si el registro se declara en
la sección de interfaz de una unidad, tiene un ámbito que incluye otras
unidades o programas que utilizan la unidad donde se produce la
declaración.
• Una matriz de registros
• Como TMember actúa como cualquier otro tipo de Object Pascal, podemos
declarar una matriz de variables de registro:

• > var DPMembers: array [1..50] de TMember;

• Para acceder al quinto miembro usamos:

• > con DPMembers [5] comenzar Nombre: = 'Nombre Apellido'; Correo electrónico: =
'FirstLast@domain.com' Publicaciones: = 0; fin ;

• O, para mostrar información (correo electrónico, por ejemplo) sobre cada


miembro que podríamos usar:

• > var k: cardinal; para k: = 1 a 50 do ShowMessage (DPMembers [k] .eMail);

• Nota: Aquí se muestra cómo declarar e inicializar una matriz constante de


registros en Delphi

• Registros como campos de registro


• Como un tipo de registro es legítimo como cualquier otro tipo Delphi,
podemos hacer que un campo de un registro sea un registro en sí mismo.
Por ejemplo, podríamos crear ExpandedMember para realizar un
seguimiento de lo que el miembro está enviando junto con la información
del miembro:

• > escriba TExpandedMember = registro SubmitType:


cadena; Miembro: TMember ; fin ;

• Completar toda la información necesaria para un solo registro ahora es de


alguna manera más difícil. Se requieren más puntos (puntos) para acceder
a los campos de TExpandedMember:

• > var SubTypeMember: TExpandedMember; SubTypeMember.SubmitType: =


'VCL'; SubTypeMember.Member.Name: = 'vcl
Programmer'; SubTypeMember.Member.eMail: =
'vcl@aboutguide.com'; SubTypeMember.Member.Name: = 555;

• Grabar con campos "desconocidos"


• Un tipo de registro puede tener una parte de variante (no me refiero a la
variable de tipo Variant). Los registros de variantes se utilizan, por ejemplo,
cuando queremos crear un tipo de registro que tenga campos para
diferentes tipos de datos, pero sabemos que nunca será necesario usar
todos los campos en una sola instancia de registro. Para obtener más
información sobre las piezas variantes en los registros, eche un vistazo a
los archivos de ayuda de Delphi. El uso de un tipo de registro variante no es
seguro para tipos y no es una práctica de programación recomendada,
especialmente para principiantes.

• Sin embargo, los registros variantes pueden ser bastante útiles, si alguna
vez se encuentra en una situación para usarlos, aquí está la segunda parte
de este artículo: "Sin embargo, los registros variantes pueden ser muy
útiles, si alguna vez se encuentra en una situación para usarlos , aquí está
la segunda parte de este artículo: Registros en Delphi - Parte 2 "

Función LeftStr
• by Zarko Gajic
• Declaración: función LeftStr ( const AString: AnsiString; const Count:
Integer): AnsiString; sobrecarga ; función LeftStr ( const AString:
WideString; const Count: Integer): WideString; sobrecarga ;

• Descripción
• Devuelve una cadena que contiene un número específico de caracteres del
lado izquierdo de una cadena.

• AString representa una expresión de cadena desde la cual se devuelven los


caracteres más a la izquierda. El recuento indica cuántos caracteres
devolver.

• Si es 0, se devuelve una cadena de longitud cero (""). Si es igual o mayor


que el número de caracteres en AString, se devuelve la cadena completa.

• Ejemplo
• var s: cadena; s: = 'SOBRE PROGRAMACIÓN DELPHI'; s: = LeftStr (s, 5); // s =
'ABOUT'

Función RightStr
• by Zarko Gajic
• Declaración: función RightStr ( const AString: AnsiString; const Count:
Integer): AnsiString; sobrecarga ; función RightStr ( const AString:
WideString; const Count: Integer): WideString; sobrecarga ;

• Descripción
• Devuelve una cadena que contiene un número específico de caracteres del
lado derecho de una cadena.

• AString representa una expresión de cadena desde la cual se devuelven los


caracteres más a la derecha. El recuento indica cuántos caracteres
devolver.
• Si es igual o mayor que el número de caracteres en AString, se devuelve la
cadena completa.

• Ejemplo
• var s: cadena; s: = 'SOBRE PROGRAMACIÓN DELPHI'; s: = RightStr (s, 5); // s =
'MMING'

Rutinas de fecha / hora - Programación


Delphi
• by Zarko Gajic
• Compara dos valores de TDateTime (devuelve "menos", "igual" o
"mayor"). Ignora la parte de tiempo si ambos valores "caen" en el mismo
día.

• Función CompareDateTime
• Compara dos valores de TDateTime (devuelve "menos", "igual" o "mayor").

• Declaración:
tipo TValueRelationship = -1..1
función CompareDateTime ( const ADate, BDate: TDateTime):
TValueRelationship

• Descripción:
Compara dos valores de TDateTime (devuelve "menos", "igual" o "mayor").

• TValueRelationship representa la relación entre dos valores. Cada uno de


los tres valores de TValueRelationship tiene una constante simbólica "me
gusta":
-1 [LessThanValue] El primer valor es menor que el segundo valor.
0 [EqualsValue] Los dos valores son iguales.
1 [GreaterThanValue] El primer valor es mayor que el segundo valor.

CompareDate resultados en:

• LessThanValue si ADate es anterior a BDate.


EqualsValue si las partes de fecha y hora de ADate y BDate son las
mismas
GreaterThanValue si ADate es posterior a BDate.

• Ejemplo:

• var ThisMoment, FutureMoment: TDateTime; ThisMoment: = Now; FutureMoment:


= IncDay (ThisMoment, 6); // agrega 6 días // CompareDateTime (ThisMoment,
FutureMoment) devuelve LessThanValue (-1) // CompareDateTime (FutureMoment,
ThisMoment) devuelve GreaterThanValue (1)

• Función CompareTime
• Compara dos valores de TDateTime (devuelve "menos", "igual" o
"mayor"). Ignora la parte Fecha si ambos valores ocurren al mismo tiempo.

• Declaración:
tipo TValueRelationship = -1..1
función CompareDate ( const ADate, BDate: TDateTime):
TValueRelationship

• Descripción:
Compara dos valores de TDateTime (devuelve "menos", "igual" o "mayor").
Ignora la parte Tiempo si ambos valores ocurren al mismo tiempo.

• TValueRelationship representa la relación entre dos valores.

• Cada uno de los tres valores de TValueRelationship tiene una constante


simbólica "me gusta":
-1 [LessThanValue] El primer valor es menor que el segundo valor.
0 [EqualsValue] Los dos valores son iguales.
1 [GreaterThanValue] El primer valor es mayor que el segundo valor.

CompareDate resultados en:

• LessThanValue si ADate ocurre antes en el día especificado por BDate.


EqualsValue si las partes de tiempo de ADate y BDate son iguales,
ignorando la parte Fecha.
GreaterThanValue si ADate ocurre más tarde en el día especificado por
BDate.

• Ejemplo:

• var ThisMoment, AnotherMoment: TDateTime; ThisMoment: = Now; OtroMomento:


= IncHour (ThisMoment, 6); // agrega 6 horas // CompareDate (ThisMoment,
AnotherMoment) devuelve LessThanValue (-1) // CompareDate (AnotherMoment,
ThisMoment) devuelve GreaterThanValue (1

• Función de fecha
• Devuelve la fecha del sistema actual.

• Declaración:
tipo TDateTime = tipo Doble;

• fecha de la función : TDateTime;


• Descripción:
Devuelve la fecha del sistema actual.

• La parte integral de un valor TDateTime es la cantidad de días que han


transcurrido desde el 30/12/1899. La parte fraccional de un valor
TDateTime es la fracción de un día de 24 horas que ha transcurrido.

• Para encontrar el número fraccionario de días entre dos fechas,


simplemente reste los dos valores. Del mismo modo, para incrementar un
valor de fecha y hora en un cierto número fraccionario de días, simplemente
agregue el número fraccionario al valor de fecha y hora.

• Ejemplo: ShowMessage ('Today is' + DateToStr (Date));

• Función DateTimeToStr
• Convierte un valor TDateTime en una cadena (fecha y hora).

• Declaración:
tipo TDateTime = tipo Doble;

• función DayOfWeek (Fecha: TDateTime): entero;

• Descripción:
Devuelve el día de la semana para una fecha determinada.

• DayOfWeek devuelve un número entero entre 1 y 7, donde el domingo es el


primer día de la semana y el sábado es el séptimo.
DayOfTheWeek no cumple con la norma ISO 8601.

• Ejemplo:

• const Days: array [1..7] de string = ('Sunday', 'Monday', 'Tuesday', 'Wednesday',


'Thursday', 'Friday', 'Saturday') ShowMessage ('Today is' + Days [DayOfWeek
(Date)]); //Hoy es Lunes

• Función DaysBetween
• Da la cantidad de días enteros entre dos fechas especificadas.

• Declaración:
función DaysBetween (const ANow, AThen: TDateTime): Integer;

• Descripción:
Da la cantidad de días enteros entre dos fechas especificadas.

• La función cuenta solo días completos. Lo que esto significa es que


devolverá 0 como resultado de la diferencia entre 05/01/2003 23:59:59 y
05/01/2003 23:59:58 - donde la diferencia real es de un * día completo
menos 1 segundo .
• Ejemplo:

• var dtNow, dtBirth: TDateTime; DaysFromBirth: entero; dtNow: = Ahora; dtBirth: =


EncodeDate (1973, 1, 29); DaysFromBirth: = DaysBetween (dtNow, dtBirth);
ShowMessage ('Zarko Gajic' existe "'+ IntToStr (DaysFromBirth) +' días completos!
');

• Función DateOf
• Devuelve solo la parte Fecha del valor TDateTime, configurando la parte
Tiempo en 0.

• Declaración:
función DateOf (Fecha: TDateTime): TDateTime

• Descripción:
Devuelve solo la parte Fecha del valor TDateTime, configurando la parte
Tiempo en 0.

• DateOf establece la porción de tiempo en 0, lo que significa medianoche.

• Ejemplo:

• var ThisMoment, ThisDay: TDateTime; ThisMoment: = Now; // -> 27/06/2003 10:


29: 16: 138 ThisDay: = DateOf (ThisMoment); // Este día: = 06/27/2003 00: 00: 00:
000

• Función DecodeDate
• Separa los valores de Año, Mes y Día desde un valor de TDateTime.

• Declaración:
procedimiento DecodeDate (Fecha: TDateTime; var Año, Mes, Día:
Palabra) ;;

• Descripción:
Separa los valores de Año, Mes y Día desde un valor de TDateTime.

• Si el valor dado de TDateTime es menor o igual a cero, los parámetros de


retorno de año, mes y día se establecen en cero.

• Ejemplo:

var Y, M, D: Word; DecodeDate (Fecha, Y, M, D); si Y = 2000 entonces ShowMessage ('¡Estás en un siglo "equivocado

• Función EncodeDate
Crea un valor de TDateTime a partir de los valores de Año, Mes y Día.
• Declaración:
función EncodeDate (año, mes, día: palabra): TDateTime

• Descripción:
Crea un valor de TDateTime a partir de los valores de Año, Mes y Día.

• El año debe estar entre 1 y 9999. Los valores de mes válidos son de 1 a 12.
Los valores de día válidos son de 1 a 28, 29, 30 o 31, según el valor del
mes.
Si la función falla, EncodeDate genera una excepción EConvertError.

• Ejemplo:

• var Y, M, D: Word; dt: TDateTime; y: = 2001; M: = 2; D: = 18; dt: = EncodeDate (Y,


M, D); ShowMessage ('Borna tendrá un año de antigüedad' + DateToStr (dt))

• Función FormatDateTime
Formatea un valor TDateTime para una cadena.

• Declaración:
función FormatDateTime ( const Fmt: cadena; Valor:
TDateTime): cadena ;

• Descripción:
Formatea un valor TDateTime para una cadena.

• FormatDateTime utiliza el formato especificado por el parámetro Fmt. Para


conocer los especificadores de formato compatibles, vaya a ver los archivos
de Ayuda de Delphi.

• Ejemplo:

• var s: cadena; d: TDateTime; ... d: = Ahora; // hoy + hora actual s: =


FormatDateTime ('dddd', d); // s: = Wednesday s: = FormatDateTime ('"Hoy es"
dddd "minute" nn', d) // s: = Hoy es miércoles, minuto 24

• Función IncDay
• Agrega o sustrae un número determinado de días desde un valor de fecha.

• Declaración:
función IncDay (ADate: TDateTime; Days: Integer = 1): TDateTime;

• Descripción:
Agrega o sustrae un número determinado de días desde un valor de fecha.

• Si el parámetro Días es negativo, la fecha devuelta es<="" p="">

• Ejemplo:
• var Fecha: TDateTime; EncodeDate (Fecha, 2003, 1, 29) // 29 de enero de 2003
IncDay (Fecha, -1) // 28 de enero de 2003

• Ahora funciona
• Devuelve la fecha y hora actual del sistema.

• Declaración:
tipo TDateTime = tipo Doble;

• función ahora: TDateTime;

• Descripción:
Devuelve la fecha y hora actual del sistema.

• La parte integral de un valor TDateTime es la cantidad de días que han


transcurrido desde el 30/12/1899. La parte fraccional de un valor
TDateTime es la fracción de un día de 24 horas que ha transcurrido.

• Para encontrar el número fraccionario de días entre dos fechas,


simplemente reste los dos valores. Del mismo modo, para incrementar un
valor de fecha y hora en un cierto número fraccionario de días, simplemente
agregue el número fraccionario al valor de fecha y hora.

• Ejemplo: ShowMessage ('Ahora es' + DateTimeToStr (Ahora));

• Años entre la función


• Da la cantidad de años enteros entre dos fechas especificadas.

• Declaración:
función YearsBetween ( const SomeDate, AnotherDate: TDateTime):
Integer;

• Descripción:
Da la cantidad de años enteros entre dos fechas especificadas.

• YearsBetween devuelve una aproximación basada en una suposición de


365.25 días por año.

• Ejemplo:

• var dtSome, dtAnother: TDateTime; DaysFromBirth: entero; dtSome: = EncodeDate


(2003, 1, 1); dtAnother: = EncodeDate (2003, 12, 31); YearsBetween (dtSome,
dtAnother) == 1 // año no bisiesto dtSome: = EncodeDate (2000, 1, 1); dtAnother:
= EncodeDate (2000, 12, 31); YearsBetween (dtSome, dtAnother) == 0 // año
bisiesto
Operaciones Básicas del Portapapeles
(Cortar / Copiar / Pegar)
• by Zarko Gajic

Usar el objeto TClipboard

El Portapapeles de Windows representa el contenedor de cualquier texto o gráfico


que se corte, copie o pegue desde o hacia una aplicación. Este artículo le
mostrará cómo utilizar el objeto TClipboard para implementar funciones de cortar,
copiar y pegar en su aplicación Delphi.

Portapapeles en General
Como probablemente sepa, el Portapapeles solo puede contener una pieza de
datos para cortar, copiar y pegar al mismo tiempo. En general, puede contener
solo una parte del mismo tipo de datos a la vez.

Si enviamos nueva información del mismo formato al Portapapeles, borramos lo


que había antes. El contenido del Portapapeles permanece en el Portapapeles
incluso después de que pegamos esos contenidos en otro programa.

TClipboard
Para utilizar el Portapapeles de Windows en nuestras aplicaciones, debemos
agregar la unidad ClipBrd a la cláusula uses del proyecto, excepto cuando
restringimos cortar, copiar y pegar a los componentes que tienen soporte
incorporado para los métodos del Portapapeles. Esos componentes son TEdit,
TMemo, TOLEContainer, TDDEServerItem, TDBEdit, TDBImage y TDBMemo.
La unidad ClipBrd crea automáticamente una instancia de un objeto TClipboard
llamado Portapapeles. Utilizaremos los métodos
CutToClipboard , CopyToClipboard , PasteFromClipboard , Clear y HasFormat par
a manejar las operaciones del portapapeles y la manipulación de texto / gráficos.

Enviar y recuperar texto


Para enviar texto al Portapapeles, se usa la propiedad AsText del objeto
Portapapeles.

Si queremos, por ejemplo, enviar la información de cadena contenida en la


variable SomeStringData al Portapapeles (borrando cualquier texto que haya),
utilizaremos el siguiente código:

> usa ClipBrd; ... Clipboard.AsText: = SomeStringData_Variable;

Para recuperar la información de texto del Portapapeles usaremos

> usa ClipBrd; ... SomeStringData_Variable: = Clipboard.AsText;


Nota: si solo queremos copiar el texto de, digamos, Editar componente al
Portapapeles, no tenemos que incluir la unidad ClipBrd en la cláusula uses. El
método CopyToClipboard de TEdit copia el texto seleccionado en el control de
edición en el Portapapeles en el formato CF_TEXT.

> procedure TForm1.Button2Click (Sender: TObject); begin // la siguiente línea seleccionará


// TODO el texto en el control de edición {Edit1.SelectAll;} Edit1.CopyToClipboard; fin ;

Imágenes del Portapapeles


Para recuperar imágenes gráficas del Portapapeles, Delphi debe saber qué tipo de
imagen se almacena allí. Del mismo modo, para transferir imágenes al
portapapeles, la aplicación debe decirle al Portapapeles qué tipo de gráficos está
enviando. Algunos de los valores posibles del parámetro Formato siguen; hay
muchos más formatos de Portapapeles proporcionados por Windows.

▪ CF_TEXT - Texto con cada línea que termina con una combinación CR-LF .
▪ CF_BITMAP : un gráfico de mapa de bits de Windows.
▪ CF_METAFILEPICT : un metarchivo de Windows gráfico.
▪ CF_PICTURE - Un objeto de tipo TPicture.
▪ CF_OBJECT - Cualquier objeto persistente.
El método HasFormat devuelve True si la imagen en el Portapapeles tiene el
formato correcto:

> si Clipboard.HasFormat (CF_METAFILEPICT) a continuación, ShowMessage ('Portapapeles


tiene metarchivo');

Para enviar (asignar) una imagen al Portapapeles, usamos el método Asignar. Por
ejemplo, el siguiente código copia el mapa de bits de un objeto de mapa de bits
llamado MyBitmap en el Portapapeles:

> Clipboard.Assign (MyBitmap);

En general, MyBitmap es un objeto de tipo TGraphics, TBitmap, TMetafile o


TPicture.

Para recuperar una imagen del Portapapeles debemos: verificar el formato de los
contenidos actuales del portapapeles y usar el método Asignar del objeto de
destino:

> {coloque un botón y un control de imagen en form1} {Antes de ejecutar este código,
presione Alt-PrintScreen key
combination} usa clipbrd; ... procedimiento TForm1.Button1Click (Sender:
TObject); comenzar si Clipboard.HasFormat
(CF_BITMAP) luego Image1.Picture.Bitmap.Assign (Portapapeles); fin;
Más control del portapapeles
El portapapeles almacena información en múltiples formatos para que podamos
transferir datos entre aplicaciones que usan formatos diferentes.

Al leer información del portapapeles con la clase TClipboard de Delphi, estamos


limitados a los formatos de portapapeles estándar: texto, imágenes y metarchivos.

Supongamos que tenemos dos aplicaciones Delphi en ejecución, ¿qué opina


sobre la definición de un formato de portapapeles personalizado para enviar y
recibir datos entre esos dos programas? Supongamos que estamos intentando
codificar un elemento de menú Pegar: queremos que se deshabilite cuando no
haya, digamos, texto en el portapapeles. Dado que todo el proceso con el
portapapeles se lleva a cabo detrás de las escenas, no hay ningún método de la
clase TClipboard que nos informe que ha habido algún cambio en el contenido del
portapapeles. Lo que necesitamos es conectar el sistema de notificación del
portapapeles, para que podamos obtener y responder a los eventos cuando
cambie el portapapeles.

Si queremos más flexibilidad y funcionalidad, tenemos que ocuparnos de las


notificaciones de cambio de portapapeles y de los formatos de portapapeles
personalizados: escuchar en el portapapeles.

Comprender el proyecto Delphi y los


archivos fuente de la unidad
• by Zarko Gajic
• Una explicación de los formatos .DPR y .PAS de Delphi

• En resumen, un proyecto Delphi es solo una colección de archivos que


componen una aplicación creada por Delphi. DPR es la extensión de
archivo utilizada para el formato de archivo Delphi Project para almacenar
todos los archivos relacionados con el proyecto. Esto incluye otros tipos de
archivos Delphi como archivos de formulario (DFM) y archivos de origen de
unidad (.PAS).

• Dado que es bastante común que las aplicaciones Delphi compartan código
o formularios previamente personalizados, Delphi organiza las aplicaciones
en estos archivos de proyecto.

• El proyecto se compone de la interfaz visual junto con el código que activa


la interfaz.

• Cada proyecto puede tener múltiples formularios que le permiten crear


aplicaciones que tienen múltiples ventanas. El código que se necesita para
un formulario se almacena en el archivo DFM, que también puede contener
información general del código fuente que puede ser compartida por todos
los formularios de la aplicación.

• Un proyecto Delphi no se puede compilar a menos que se use un archivo


de recursos de Windows (RES), que contiene el icono del programa y la
información de la versión. También podría contener otros recursos, como
imágenes, tablas, cursores, etc. Los archivos RES son generados
automáticamente por Delphi.

• Nota: Los archivos que terminan en la extensión de archivo DPR también


son archivos de Digital InterPlot utilizados por el programa Bentley Digital
InterPlot, pero no tienen nada que ver con los proyectos de Delphi.

• Más información sobre archivos DPR


• El archivo DPR contiene directorios para compilar una aplicación.
Normalmente, este es un conjunto de rutinas simples que abren el
formulario principal y cualquier otra forma que se configure para abrirse
automáticamente.

• A continuación, inicia el programa llamando a los


métodos Initialize , CreateForm y Run del objeto Application global.

• La aplicación de variable global, de tipo TApplication, está en cada


aplicación Delphi Windows. La aplicación encapsula su programa y
proporciona muchas funciones que ocurren en el fondo del software.

• Por ejemplo, la Aplicación maneja cómo llamarías a un archivo de ayuda


desde el menú de tu programa.

• DPROJ es otro formato de archivo para los archivos del Proyecto Delphi,
pero almacena la configuración del proyecto en formato XML.

• Más información sobre archivos PAS


• El formato de archivo PAS está reservado para los archivos fuente de la
unidad Delphi. Puede ver el código fuente del proyecto actual a través del
menú Proyecto> Ver fuente .

• Aunque puede leer y editar el archivo del proyecto como lo haría con
cualquier código fuente, en la mayoría de los casos, permitirá que Delphi
mantenga el archivo DPR. La razón principal para ver el archivo del
proyecto es ver las unidades y formularios que componen el proyecto, así
como para ver qué formulario se especifica como el formulario "principal" de
la aplicación.

• Otra razón para trabajar con el archivo de proyecto es cuando está creando
un archivo DLL en lugar de una aplicación independiente. O bien, si
necesita algún código de inicio, como una pantalla de bienvenida antes de
que Delphi cree el formulario principal.

• Este es el código fuente del archivo de proyecto predeterminado para una


nueva aplicación que tiene un formulario llamado "Form1:"

• > programa Project1; usa Formularios, Unidad1 en 'Unidad1.pas' { Formulario1 } ; {$


R * .RES} begin Application.Initialize; Application.CreateForm (TForm1,
Form1); Aplicación.Ejecutar; fin

• A continuación hay una explicación de cada uno de los componentes del


archivo PAS:

• " programa "

• Esta palabra clave identifica a esta unidad como la unidad fuente principal
del programa. Puede ver que el nombre de la unidad, "Proyecto1", sigue la
palabra clave del programa. Delphi le da al proyecto un nombre
predeterminado hasta que lo guarde como algo diferente.

• Cuando ejecuta un archivo de proyecto desde el IDE, Delphi usa el nombre


del archivo de Proyecto para el nombre del archivo EXE que crea. Lee la
cláusula "usos" del archivo de proyecto para determinar qué unidades son
parte de un proyecto.

• " {$ R * .RES} "

• El archivo DPR está vinculado al archivo PAS con la directiva de


compilación {$ R * .RES} . En este caso, el asterisco representa la raíz del
nombre del archivo PAS en lugar de "cualquier archivo". Esta directiva de
compilación le dice a Delphi que incluya el archivo de recursos de este
proyecto, como su imagen de icono.

• " comenzar y terminar "

• El bloque "comenzar" y "finalizar" es el bloque de código fuente principal


para el proyecto.

• " Inicializar "

• Aunque "Inicializar" es el primer método llamado en el código


fuente principal, no es el primer código que se ejecuta en una aplicación. La
aplicación primero ejecuta la "inicialización" sección de todas las unidades
utilizadas por la aplicación.

• " Application.CreateForm "


• La instrucción "Application.CreateForm" carga el formulario especificado en
su argumento. Delphi agrega una declaración Application.CreateForm al
archivo de proyecto para cada formulario que se incluye.

• El trabajo de este código es asignar primero memoria para el formulario.


Las declaraciones se enumeran en el orden en que los formularios se
agregan al proyecto. Este es el orden en que se crearán los formularios en
la memoria en tiempo de ejecución.

• Si desea cambiar este orden, no edite el código fuente del proyecto. En su


lugar, use el menú Proyecto> Opciones .

• " Aplicación.Ejecutar "

• La instrucción "Application.Run" inicia la aplicación. Esta instrucción le dice


al objeto pre-declarado llamado Aplicación, que comience a procesar los
eventos que ocurren durante la ejecución de un programa.

• Ejemplo de ocultar el formulario principal / botón de la barra de tareas


• La propiedad "ShowMainForm" del objeto Aplicación determina si un
formulario se mostrará o no al inicio. La única condición para establecer
esta propiedad es que debe llamarse antes de la línea "Application.Run".

• > // Presumir: Form1 es el FORMULARIO PRINCIPAL Application.CreateForm


(TForm1, Form1); Application.ShowMainForm: = Falso; Aplicación.Ejecutar;

Comprensión y uso de funciones y


procedimientos
• by Zarko Gajic

para principiantes Delphi ...

¿Alguna vez te has encontrado escribiendo el mismo código una y otra vez para
realizar alguna tarea común dentro de los manejadores de eventos? ¡Sí! Es hora
de que aprenda sobre los programas dentro de un programa. Llamemos a esos
mini programas subrutinas.

Introducción a subrutinas

Las subrutinas son una parte importante de cualquier lenguaje de programación, y


Delphi no es una excepción. En Delphi, generalmente hay dos tipos de subrutinas:
una función y un procedimiento . La diferencia habitual entre una función y un
procedimiento es que una función puede devolver un valor, y un
procedimiento generalmente no lo hará . Una función normalmente se llama
como parte de una expresión.
Echa un vistazo a los siguientes ejemplos:

> procedimiento SayHello ( const sWhat: cadena ); comenzar ShowMessage


('Hello' + sWhat); fin ; función YearsOld ( const BirthYear: integer): entero; Var Año,
Mes, Día: Palabra; comenzar DecodeDate (Fecha, Año, Mes, Día); Resultado: = Año -
AniversarioAño; fin ; Una vez definidas las subrutinas, podemos llamarlas una o
más veces: > procedure TForm1.Button1Click (Sender: TObject); comenzar SayHello
('Usuario de Delphi'); fin ; procedure TForm1.Button2Click (Sender:
TObject); comenzar SayHello ('Zarko Gajic'); ShowMessage ('Usted es' + IntToStr
(AñosOld (1973)) + 'años de edad!'); fin ;

Funciones y procedimientos

Como podemos ver, tanto las funciones como los procedimientos actúan como
mini programas. En particular, pueden tener su propio tipo, constantes y
declaraciones de variables dentro de ellos.
Eche un vistazo más de cerca a una función SomeCalc (miscelánea):

> función SomeCalc ( const sStr: string ; const iYear, iMonth: integer; var iDay:
integer): boolean; comenzar ... finalizar ; Cada procedimiento o función comienza
con un encabezado que identifica el procedimiento o función y enumera
los parámetros que utiliza la rutina, si corresponde. Los parámetros se enumeran
entre paréntesis. Cada parámetro tiene un nombre de identificación y
generalmente tiene un tipo. Un punto y coma separa los parámetros en una lista
de parámetros entre sí.
sStr, iYear e iMonth se llaman parámetros constantes . La función (o
procedimiento) no puede cambiar los parámetros constantes. El iDay se pasa
como un parámetro var , y podemos hacer cambios en él, dentro de la subrutina.

Las funciones, dado que devuelven valores, deben tener un tipo de


devolución declarado al final del encabezado. El valor de retorno de una función
viene dado por la asignación (final) a su nombre. Dado que cada función tiene
implícitamente una variable local Resultado del mismo tipo que las funciones
devuelven valor, la asignación a Resultado tiene el mismo efecto que la asignación
al nombre de la función.

Subrutinas de posicionamiento y llamadas

Las subrutinas siempre se ubican dentro de la sección de implementación de la


unidad. Tales subrutinas pueden ser llamadas (usadas) por cualquier manejador de
eventos o subrutinas en la misma unidad que se define después.
Nota: la cláusula uses de una unidad te dice a qué unidades puede llamar. Si
queremos que una subrutina específica en una Unidad1 sea utilizable por los
manejadores de eventos o subrutinas en otra unidad (digamos Unidad 2), tenemos
que:

▪ Agregue Unit1 a la cláusula uses de Unit2

▪ Coloque una copia del encabezado de la subrutina en la sección de interfaz de


la Unidad1.
Esto significa que las subrutinas cuyos encabezados se proporcionan en la sección
de interfaz son de alcance global .
Cuando llamamos a una función (o un procedimiento) dentro de su propia unidad,
usamos su nombre con los parámetros que sean necesarios. Por otro lado, si
llamamos a una subrutina global (definida en alguna otra unidad, por ejemplo,
MyUnit), usamos el nombre de la unidad seguido de un punto.

> ... // El procedimiento de SayHello se define dentro de esta unidad SayHello


('Usuario de Delphi'); // La función Years Old se define dentro de la unidad
MyUnit. Dummy: = MyUnit.YearsOld (1973); ... Nota: las funciones o procedimientos
pueden tener sus propias subrutinas incrustadas dentro de ellos. Una subrutina
incrustada es local a la subrutina del contenedor y no puede ser utilizada por otras
partes del programa. Algo así como: > procedure TForm1.Button1Click (Sender:
TObject); función IsSmall ( const sStr: cadena ): booleano; begin // IsSmall devuelve
True si sStr está en minúscula, False en caso contrario Resultado: = LowerCase (sStr)
= sStr; fin ; begin // IsSmall solo se puede usar dentro de Button1 Evento
OnClick si IsSmall (Edit1.Text) luego ShowMessage ('Todas las pequeñas letras
mayúsculas en Edit1.Text') else ShowMessage ('No todas las pequeñas letras
mayúsculas en Edit1.Text'); fin ;
Recursos Relacionados:

▪ Sobrecarga y parámetros opcionales / por defecto


▪ Cómo usar una función o un procedimiento como parámetro en otra función
▪ Cómo ejecutar un método (procedimiento / función) por nombre

Cómo usar una función o un


procedimiento como parámetro en otra
función
• by Zarko Gajic
En Delphi , los tipos de procedimientos (punteros de método) le permiten tratar
procedimientos y funciones como valores que se pueden asignar a variables o
pasar a otros procedimientos y funciones.

A continuación, se indica cómo llamar a una función (o procedimiento) como un


parámetro de otra función (o procedimiento):

1. Declare la función (o procedimiento) que se usará como parámetro. En el


ejemplo a continuación, esto es "TFunctionParameter".
2. Define una función que aceptará otra función como parámetro. En el siguiente
ejemplo, esto es "DynamicFunction"
> tipo TFunctionParameter = function ( const value:
integer): cadena ; ... función Uno (valor constante :
entero): cadena ; comenzar resultado: = IntToStr (valor); fin ; función Dos
(valor constante : entero): cadena ; begin result: = IntToStr (valor 2
*); fin ; función DynamicFunction (f: TFunctionParameter): cadena ; comenzar
el resultado: = f (2006); fin ; ... // Ejemplo de uso: var s: string; begin s: =
DynamicFunction (One); ShowMessage (s); // mostrará "2006" s: = DynamicFunction
(Dos); ShowMessage (s); // mostrará el final "4012" ;
Nota:

▪ Por supuesto, usted decide sobre la firma del "Parámetro TFunction": si se trata
de un procedimiento o una función, cuántos parámetros se necesitan, etc.
▪ Si "TFunctionParameter" es un método (de un objeto de instancia), debe
agregar las palabras de objeto al nombre de tipo de procedimiento, como en:
TFunctionParameter = function (const value: integer): cadena de objetos;

▪ Si espera que se especifique "nil" como el parámetro "f", debe probarlo con la
función Asignada .
▪ Reparar el puntero del método "Tipo incompatible: 'y el procedimiento regular'"

La clase TStream en Delphi


• by Zarko Gajic

¿Qué es una corriente? TStream?

Una secuencia es lo que su nombre sugiere: un "río de datos" que fluye. Una
secuencia tiene un principio, un final, y siempre estás en algún punto intermedio
de estos dos puntos.
Con los objetos TStream de Delphi puede leer o escribir en varios tipos de medios
de almacenamiento, como archivos de disco, memoria dinámica, etc.

¿Qué datos puede contener una secuencia?

Una transmisión puede contener todo lo que desee, en el orden que desee.

En el proyecto de ejemplo que acompaña este artículo, los registros de tamaño fijo
se utilizan con fines de simplicidad, pero puede escribir cualquier combinación de
datos de tamaño variable en una secuencia. Recuerde, sin embargo, que _usted_
es responsable de la casa. ¡No hay forma de que Delphi "recuerde" qué tipo de
datos hay en una transmisión o en qué orden!

Streams Versus Arrays

Las matrices tienen la desventaja de tener un tamaño fijo que debe conocerse en
tiempo de compilación. Ok, puedes usar matrices dinámicas.

Por otro lado, una transmisión puede crecer hasta el tamaño de la memoria
disponible, que es considerablemente más grande en los sistemas actuales, sin
tareas domésticas.

Una secuencia no puede ser indexada, como una matriz puede. Pero como verá a
continuación, "caminar" arriba y abajo de un arroyo es muy fácil.

Las secuencias se pueden guardar / cargar en / desde archivos en una sola


operación.

Sabores de las corrientes

TStream es el tipo de clase base (abstracta) para los objetos de transmisión. Ser
abstracto significa que TStream nunca se debe usar como tal, sino solo en sus
formas descendientes.

Para transmitir cualquier tipo de información, elija una clase descendiente según
los datos específicos y las necesidades de almacenamiento. Por ejemplo:

▪ TFileStream (para trabajar con archivos)


▪ TMemoryStream (para trabajar con un buffer de memoria)
▪ TStringStream (para manipular cadenas en memoria)
▪ TBlobStream (para trabajar con campos BLOB)

▪ TWinSocketStream (para leer y escribir en una conexión de socket)


▪ TOleStream (para usar una interfaz COM para leer y escribir)
Como verá, TmemoryStream y TFileStream son notablemente intercambiables y
compatibles.

Extensiones de nombre de archivo en


Delphi
• by Zarko Gajic
• Delphi emplea una cantidad de archivos para su configuración, algunos
globales para el entorno Delphi, algunos específicos del proyecto. Varias
herramientas en Delphi IDE almacenan datos en archivos de otros tipos.

• La siguiente lista describe los archivos y las extensiones de nombre de


archivo que Delphi crea para una aplicación autónoma típica, más una
docena más. Además, conozca qué archivos generados por Delphi deben
almacenarse en un sistema de control de origen.

• Delphi Project Specific


• .PAS - Archivo fuente Delphi
PAS debe almacenarse en Source Control
En Delphi, los archivos PAS siempre son el código fuente de una unidad o
un formulario. Los archivos fuente de la unidad contienen la mayor parte del
código en una aplicación. La unidad contiene el código fuente para
cualquier manejador de eventos adjunto a los eventos del formulario o los
componentes que contiene. Podemos editar archivos .pas usando el editor
de código de Delphi. No borre los archivos .pas.

• .DCU - Unidad compilada de Delphi


Un archivo de unidad compilada (.pas). Por defecto, la versión compilada
de cada unidad se almacena en un archivo de formato binario separado con
el mismo nombre que el archivo de unidad, pero con la extensión .DCU
(unidad compilada de Delphi). Por ejemplo unit1.dcu contiene el código y
los datos declarados en el archivo unit1.pas. Cuando reconstruye un
proyecto, las unidades individuales no se vuelven a compilar a menos que
sus archivos de origen (.PAS) hayan cambiado desde la última compilación
o no se puedan encontrar sus archivos .DCU.

• Elimine de forma segura el archivo .dcu porque Delphi lo recrea cuando


compila la aplicación.

• .DFM - Formulario Delphi


DFM debe almacenarse en Source Control
Estos archivos siempre están vinculados con archivos .pas. Un archivo
DFM contiene los detalles (propiedades) de los objetos contenidos en un
formulario. Se puede ver como texto haciendo clic derecho en el formulario
y seleccionando ver como texto en el menú emergente.
• Delphi copia información en archivos .dfm en el archivo de código .exe
terminado. Se debe tener precaución al modificar este archivo, ya que los
cambios en él podrían evitar que el IDE pueda cargar el formulario. Los
archivos de formulario se pueden guardar en formato binario o de texto. El
cuadro de diálogo Opciones de entorno le permite indicar qué formato
desea usar para los formularios recién creados. No elimine archivos .dfm.

• .DPR - Proyecto Delphi


DPR debe almacenarse en Source Control
El archivo .DPR es el archivo central de un proyecto Delphi (un archivo .dpr
por proyecto), en realidad un archivo fuente de Pascal. Sirve como el punto
de entrada principal para el ejecutable. El DPR contiene las referencias a
los otros archivos en el proyecto y vincula formularios con sus unidades
asociadas. Aunque podemos modificar el archivo .DPR, no deberíamos
modificarlo manualmente. No elimine archivos .DPR.

• .RES - Archivo de recursos de Windows


Un archivo de recursos de Windows generado automáticamente por Delphi
y requerido por el proceso de compilación. Este archivo de formato binario
contiene el recurso de información de versión (si es necesario) y el ícono
principal de la aplicación. El archivo también puede contener otros recursos
utilizados dentro de la aplicación, pero estos se conservan tal cual.

• .EXE - Ejecutable de la aplicación


La primera vez que creamos una aplicación o una biblioteca estándar de
enlace dinámico, el compilador produce un archivo .DCU para cada nueva
unidad utilizada en su proyecto; todos los archivos .DCU de su proyecto se
vinculan para crear un único archivo .EXE (ejecutable) o .DLL.

• Este archivo de formato binario es el único (en la mayoría de los casos) que
debe distribuir a sus usuarios. Borre de forma segura su archivo .exe de
proyectos porque Delphi lo recrea cuando compila la aplicación.

• . ~ ?? - Archivos de copia de seguridad Delphi


Archivos con nombres que terminan en ~ ~ ?? (por ejemplo, unit2. ~ pa) son
copias de seguridad de archivos modificados y guardados. Elimine esos
archivos de forma segura en cualquier momento, sin embargo, es posible
que desee conservarlos para recuperar la programación dañada.

• .DLL - Extensión de aplicación


Código para la biblioteca de enlaces dinámicos . Una biblioteca de vínculos
dinámicos (DLL) es una colección de rutinas a las que las aplicaciones y
otras DLL pueden llamar. Como las unidades, las DLL contienen código o
recursos que se pueden compartir. Pero una DLL es un ejecutable
compilado por separado que está vinculado en tiempo de ejecución a los
programas que lo usan. No elimine un archivo .DLL a menos que lo haya
escrito. Vaya a ver las DLL y Delphi para obtener más información sobre la
programación.

• .DPK - Paquete Delphi


DPK debe almacenarse en Source Control
Este archivo contiene el código fuente de un paquete, que a menudo es una
colección de varias unidades. Los archivos fuente del paquete son similares
a los archivos del proyecto, pero se usan para construir bibliotecas
especiales de enlaces dinámicos llamadas paquetes. No elimine archivos
.dpk.

• .DCP
Este archivo de imagen binaria consiste en el paquete compilado real. La
información del símbolo y la información del encabezado adicional
requerida por el IDE están todas contenidas dentro del archivo .DCP. El IDE
debe tener acceso a este archivo para construir un proyecto. No elimine
archivos .DCP.

• .BPL o .DPL
Este es el paquete de tiempo de diseño o tiempo de ejecución real. Este
archivo es una DLL de Windows con características específicas de Delphi
integradas. Este archivo es esencial para la implementación de una
aplicación que usa un paquete. En la versión 4 y superior, esta es la
"biblioteca de paquetes de Borland" en la versión 3, es la "biblioteca de
paquetes de Delphi". Consulte BPL vs. DLL para obtener más información
sobre la programación con paquetes.

• La siguiente lista describe los archivos y las extensiones de nombre de


archivo que Delphi IDE crea para una aplicación autónoma típica

• IDE específico
.BPG, .BDSGROUP - Borland Project Group ( Borland Developer Studio
Project Group )
BPG debe almacenarse en Source Control
Cree grupos de proyectos para manejar proyectos relacionados a la vez.
Por ejemplo, puede crear un grupo de proyectos que contenga varios
archivos ejecutables, como .DLL y .EXE.

• .DCR
DCR debe almacenarse en Source Control
Los archivos de recursos del componente Delphi contienen el ícono de un
componente tal como aparece en la paleta de VCL. Podemos usar archivos
.dcr cuando construyamos nuestros propios componentes personalizados .
No elimine archivos .dpr.

• .DOF
DOF debe ser almacenado en Source Control
Este archivo de texto contiene la configuración actual para las opciones del
proyecto, como la configuración del compilador y el enlazador, directorios,
directivas condicionales y parámetros de línea de comandos . La única
razón para eliminar el archivo .dof es volver a las opciones estándar para
un proyecto.

• .DSK
Este archivo de texto almacena información sobre el estado de su proyecto,
como qué ventanas están abiertas y en qué posición se encuentran. Esto le
permite restaurar el espacio de trabajo de su proyecto cada vez que vuelva
a abrir el proyecto Delphi.

• .DRO
Este archivo de texto contiene información sobre el repositorio de objetos.
Cada entrada en este archivo contiene información específica sobre cada
elemento disponible en el repositorio de objetos.

• .DMT
Este archivo binario patentado contiene la información de plantillas de menú
enviada y definida por el usuario.

• .TLB
El archivo es un archivo de biblioteca de tipo binario patentado. Este
archivo proporciona una forma de identificar qué tipos de objetos e
interfaces están disponibles en un servidor ActiveX. Al igual que una unidad
o un archivo de encabezado, .TLB sirve como un repositorio de información
de símbolos necesaria para una aplicación.

• .DEM
Este archivo de texto contiene algunos formatos estándar específicos del
país para un componente TMaskEdit.

• La lista de las extensiones de archivos que ve cuando se desarrolla con


Delphi continúa ...

• .TAXI
Este es el formato de archivo que Delphi ofrece a sus usuarios para la
implementación web. El formato de gabinete es una forma eficiente de
empaquetar varios archivos.

• .DB
Los archivos con esta extensión son archivos estándar de Paradox.

• .DBF
Los archivos con esta extensión son archivos dBASE estándar.

• .GDB
Los archivos con esta extensión son archivos estándar de Interbase.
• .DBI
Este archivo de texto contiene información de inicialización para el
Explorador de la base de datos.

• Precaución
Nunca elimine archivos con nombres que terminen en .dfm, .dpr o .pas, a
menos que desee descartar su proyecto. Estos archivos contienen las
propiedades y el código fuente de la aplicación. Al hacer una copia de
seguridad de una aplicación, estos son los archivos críticos para guardar.

Anatomía de una unidad Delphi (Delphi


para principiantes)
• by Zarko Gajic
• Delphi para principiantes :

• Interfaz, Implementación, Inicialización, Finalización, Usos y otras


palabras "divertidas"!
• Si planea ser un buen programador de Delphi, las palabras como la interfaz,
la implementación y los usos deben tener un lugar especial en su
conocimiento de programación.

• Proyectos Delphi
• Cuando creamos una aplicación Delphi, podemos comenzar con un
proyecto en blanco, un proyecto existente o una de las aplicaciones o
plantillas de formularios de Delphi.

• Un proyecto consta de todos los archivos necesarios para crear nuestra


aplicación de destino.
El cuadro de diálogo que aparece cuando elegimos View-Project Manager
nos permite acceder a la forma y las unidades de nuestro proyecto.
Un proyecto se compone de un único archivo de proyecto (.dpr) que
enumera todas las formas y unidades del proyecto. Podemos ver e incluso
editar el archivo de proyecto (llamémoslo una unidad de proyecto )
eligiendo Ver - Fuente del proyecto. Debido a que Delphi mantiene el
archivo del proyecto, normalmente no deberíamos modificarlo
manualmente, y en general no se recomienda para programadores
inexpertos hacerlo.

• Unidades Delphi
• Como sabemos hasta ahora, las formas son parte visible de la mayoría de
los proyectos de Delphi. Cada formulario en un proyecto Delphi también
tiene una unidad asociada. La unidad contiene el código fuente para
cualquier manejador de eventos adjunto a los eventos del formulario o los
componentes que contiene.

• Como las unidades almacenan el código para su proyecto, las unidades


son básicas para la programación de Delphi .

• En términos generales, la unidad es una colección de constantes, variables,


tipos de datos y procedimientos y funciones que pueden ser compartidas
por varias aplicaciones.

• Cada vez que creamos un nuevo formulario (archivo .dfm), Delphi crea
automáticamente su unidad asociada (archivo .pas), vamos a llamarlo
una Unidad de Formulario . Sin embargo, las unidades no tienen que estar
asociadas con formularios.

• Una Unidad de código contiene código que se llama desde otras unidades
en el proyecto. Cuando empiece a construir bibliotecas de rutinas útiles,
probablemente las almacene en una unidad de código. Para agregar una
nueva unidad de código a la aplicación Delphi, seleccione Archivo-Nuevo ...
Unidad.

• Anatomía
• Cada vez que creamos una unidad (formulario o unidad de código) Delphi
agrega automáticamente las siguientes secciones de código: encabezado
de la unidad, sección de interfaz , sección de implementación . También
hay dos secciones opcionales: inicialización y finalización .

• Como verá, las unidades deben estar en un formato predefinido para que el
compilador pueda leerlas y compilar el código de la unidad.

• El encabezado de la unidad comienza con la unidad de palabra reservada,


seguida del nombre de la unidad. Necesitamos usar el nombre de la unidad
cuando nos referimos a la unidad en la cláusula de usos de otra unidad.

• Sección de interfaz
• Esta sección contiene la cláusula uses que enumera las otras unidades
(código o unidades de formulario) que utilizará la unidad. En el caso de las
unidades de formulario, Delphi agrega automáticamente las unidades
estándar como Windows, Mensajes, etc. A medida que agrega nuevos
componentes a un formulario, Delphi agrega los nombres apropiados a la
lista de usos. Sin embargo, Delphi no agrega una cláusula de uso a la
sección de interfaz de las unidades de código, tenemos que hacerlo
manualmente.

• En la sección de interfaz de la unidad, podemos declarar


constantes globales , tipos de datos, variables, procedimientos y funciones.
Trataré con alcance variable; procedimientos y funciones en algunos
artículos futuros.

• Tenga en cuenta que Delphi crea una unidad de formulario para usted a
medida que diseña un formulario. El tipo de datos de formulario, la variable
de formulario que crea una instancia del formulario y los controladores de
eventos se declaran en la parte de interfaz.
Debido a que no es necesario sincronizar el código en unidades de código
con una forma asociada, Delphi no mantiene la unidad de código para
usted.

• La sección de interfaz finaliza en la implementación de palabra reservada.

• Sección de implementación
• La sección de implementación de una unidad es la sección que contiene el
código real de la unidad. La implementación puede tener declaraciones
adicionales propias, aunque estas declaraciones no son accesibles a
ninguna otra aplicación o unidad.

• Cualquier objeto Delphi declarado aquí estaría disponible solo para codificar
dentro de la unidad (global a la unidad). Una cláusula de uso opcional
puede aparecer en la parte de implementación e inmediatamente debe
seguir la palabra clave de implementación.

• Secciones de inicialización y finalización


• Estas dos secciones son opcionales; no se generan automáticamente
cuando creamos una unidad. Si queremos inicializar los datos que
utiliza la unidad, podemos agregar un código de inicialización a la
sección de inicialización de la unidad. Cuando una aplicación utiliza una
unidad, se llama al código dentro de la parte de inicialización de la
unidad antes de que se ejecute cualquier otro código de la aplicación.
• Si su unidad necesita realizar una limpieza cuando finaliza la aplicación,
como liberar los recursos asignados en la parte de inicialización; puede
agregar una sección de finalización a su unidad. La sección de finalización
viene después de la sección de inicialización, pero antes del final final.

Trampas de la declaración If-Then-Else en


el código Delphi
• by Zarko Gajic

Principiantes desarrolladores de Delphi: cuidado con las trampas If Then Else


En Delphi , la instrucción if se utiliza para probar una condición y luego ejecutar
secciones de código en función de si esa condición es verdadera o falsa.

Una declaración if-then-else general se ve así:

> if luego else ;

Tanto el "bloque verdadero" como el "bloque falso" pueden ser una declaración
simple o una declaración estructurada (rodeada con un par de inicio-final).

Consideremos un ejemplo usando declaraciones if anidadas:

> j: = 50; si j> = 0, entonces si j = 100, entonces Subtítulo: = '¡El número es


100!' else Leyenda: = '¡El número es NEGATIVO!'; v

¿Cuál será el valor de "Cation"? Respuesta: "¡El número es NEGATIVO!" ¿No


esperaba eso?

Tenga en cuenta que el compilador no tiene en cuenta su formato, podría haber


escrito lo anterior como:

> j: = 50; si j> = 0, entonces si j = 100, entonces Subtítulo: = '¡El número es


100!' else Leyenda: = '¡El número es NEGATIVO!'; v

o incluso como (todo en una línea):

> j: = 50; si j> = 0, entonces si j = 100, entonces Subtítulo: = '¡El número es


100!' else Leyenda: = '¡El número es NEGATIVO!'; v

Los ";" marca el final de una declaración.

El compilador leerá la declaración anterior como:

> j: = 50; si j> = 0, entonces si j = 100, entonces Subtítulo: = '¡El número es


100!' else Leyenda: = '¡El número es NEGATIVO!';

o para ser más preciso:

> j: = 50; si j> = 0, entonces comienza si j = 100, entonces Subtítulo: = '¡El número es
100!' else Leyenda: = '¡El número es NEGATIVO!'; fin ;

Nuestra declaración ELSE se interpretará como una parte de la declaración IF


"interna". La instrucción "interna" es una declaración cerrada y no necesita un
BEGIN..ELSE.

Para asegurarse de que sabe cómo el compilador trata las declaraciones if


anidadas y de corregir el "problema" anterior, puede escribir la versión inicial como
sigue:
> j: = 50; si j> = 0, entonces si j = 100, entonces Subtítulo: = '¡El número es
100!' else else Leyenda: = '¡El número es NEGATIVO!';

Uh! El "else" feo termina la línea si anidada? Compila, funciona!

La mejor solución es: siempre use pares de inicio y final con declaraciones if
anidadas:

> j: = 50; si j> = 0, entonces comienza si j = 100, entonces Subtítulo: = '¡El número es
100!'; end else begin Caption: = '¡El número es NEGATIVO!'; fin ;

¿Demasiados pares de inicio y fin para ti? ¡Más vale prevenir que curar! De todos
modos, las plantillas de código están diseñadas para agregar estructuras de
esqueleto comúnmente utilizadas a su código fuente y luego completarlas.

Más sobre el código Delphi

▪ ¿Qué significa # 13 # 10, en Delphi Code?


▪ Ejecutar y ejecutar aplicaciones y archivos desde el código Delphi
▪ Revisión ortográfica del código Delphi con MS Word
▪ Operaciones Básicas del Portapapeles (Cortar / Copiar / Pegar)

Ejecutar y ejecutar aplicaciones y


archivos desde el código Delphi
• by Zarko Gajic
• Ejemplos que utilizan la función ShellExecute API de Windows

• El lenguaje de programación Delphi proporciona una forma rápida de


escribir, compilar, empaquetar e implementar aplicaciones multiplataforma.
Aunque Delphi crea una interfaz gráfica de usuario, es probable que haya
ocasiones en las que desee ejecutar un programa desde su código Delphi.
Supongamos que tiene una aplicación de base de datos que utiliza una
utilidad de copia de seguridad externa. La utilidad de copia de seguridad
toma los parámetros de la aplicación y los archiva, mientras que el
programa espera hasta que finalice la copia de seguridad.

• Tal vez quiera abrir documentos presentados en un cuadro de lista de


archivos simplemente haciendo doble clic en ellos sin abrir primero el
programa asociado. Imagine una etiqueta de enlace en su programa que
lleva al usuario a su página de inicio. ¿Qué opina sobre enviar un correo
electrónico directamente desde su aplicación Delphi a través del programa
predeterminado de cliente de correo electrónico de Windows?
• ShellExecute
• Para iniciar una aplicación o ejecutar un archivo en el entorno Win32, use la
función ShellExecute Windows API. Consulte la ayuda en ShellExecute
para obtener una descripción completa de los parámetros y códigos de
error devueltos. Puede abrir cualquier documento sin saber a qué programa
está asociado: el enlace está definido en el Registro de Windows .

• Aquí hay algunos ejemplos de shell.

• Ejecutar el Bloc de notas


• usa ShellApi; ... ShellExecute (Handle, 'open', 'c: \ Windows \ notepad.exe', nil, nil,
SW_SHOWNORMAL);

• Abre SomeText.txt con el Bloc de notas


• ShellExecute (Handle, 'open', 'c: \ windows \ notepad.exe', 'c: \ SomeText.txt', nil,
SW_SHOWNORMAL);

• Mostrar el contenido de la carpeta "DelphiDownload"


• ShellExecute (Handle, 'open', 'c: \ DelphiDownload', nil, nil, SW_SHOWNORMAL);

• Ejecutar un archivo de acuerdo a su extensión


• ShellExecute (Handle, 'open', 'c: \ MyDocuments \ Letter.doc', nil, nil,
SW_SHOWNORMAL);

• A continuación, le mostramos cómo encontrar una aplicación asociada con


una extensión.

• Abra un sitio web o un archivo * .htm con el explorador web


predeterminado
• ShellExecute (Handle, 'open', 'http: //delphi.about.com',nil,nil, SW_SHOWNORMAL);

• Enviar un correo electrónico con el asunto y el cuerpo del mensaje


• var em_subject, em_body, em_mail: string; begin em_subject: = 'Esta es la línea de
asunto'; em_body: = 'El texto del cuerpo del mensaje va aquí'; em_mail: = 'mailto:
delphi@aboutguide.com? subject =' + em_subject + '& body =' + em_body;
ShellExecute (Handle, 'open', PChar (em_mail), nil, nil, SW_SHOWNORMAL); fin;

• A continuación, le indicamos cómo enviar un correo electrónico con el


archivo adjunto .

• Ejecute un programa y espere hasta que termine


• El siguiente ejemplo usa la función ShellExecuteEx API.

• // Ejecute la Calculadora de Windows y aparezca // un mensaje cuando termine


Calc. usa ShellApi; ... var SEInfo: TShellExecuteInfo; ExitCode: DWORD; ExecuteFile,
ParamString, StartInString: cadena; begin ExecuteFile: = 'c: \ Windows \ Calc.exe';
FillChar (SEInfo, SizeOf (SEInfo), 0); SEInfo.cbSize: = SizeOf (TShellExecuteInfo); con
SEInfo comienzan fMask: = SEE_MASK_NOCLOSEPROCESS; Wnd: =
Application.Handle; lpFile: = PChar (ExecuteFile); {ParamString puede contener los
parámetros de la aplicación. } // lpParameters: = PChar (ParamString); {StartInString
especifica el nombre del directorio de trabajo. Si se omite, se usa el directorio
actual. } // lpDirectory: = PChar (StartInString); nMostrar: = SW_SHOWNORMAL; fin;
si ShellExecuteEx (@SEInfo) a continuación, repita Application.ProcessMessages;
GetExitCodeProcess (SEInfo.hProcess, ExitCode); until (ExitCode <> STILL_ACTIVE) o
Application.Terminated; ShowMessage ('Calculadora terminada'); end else
ShowMessage ('¡Error al iniciar Calc!'); fin;

Optimización del uso de la memoria de su


programa Delphi
• by Zarko Gajic
• administrador de la barra de tareas de Windows.

• Al escribir aplicaciones de larga ejecución, el tipo de programas que


pasarán la mayor parte del día minimizados en la barra de tareas o en
la bandeja del sistema , puede ser importante no permitir que el programa
se "escape" con el uso de la memoria.

• Aprenda a limpiar la memoria utilizada por su programa Delphi usando la


función SetProcessWorkingSetSize Windows API.

• Uso de memoria de un programa / aplicación / proceso


• Eche un vistazo a la captura de pantalla del Administrador de tareas de
Windows ...

• Las dos columnas más a la derecha indican el uso de la CPU (tiempo) y el


uso de la memoria. Si un proceso impacta severamente en alguno de estos,
su sistema se ralentizará.

• El tipo de cosa que con frecuencia afecta el uso de la CPU es un programa


que está en bucle (pregunte a cualquier programador que haya olvidado
poner una instrucción "leer siguiente" en un bucle de procesamiento de
archivos). Esos tipos de problemas generalmente se corrigen fácilmente.

• El uso de la memoria, por otro lado, no siempre es evidente, y necesita ser


gestionado más que corregido. Supongamos, por ejemplo, que se está
ejecutando un programa de tipo de captura.
• Este programa se usa durante todo el día, posiblemente para la captura
telefónica en un servicio de ayuda, o por alguna otra razón. Simplemente no
tiene sentido apagarlo cada veinte minutos y luego volverlo a encender. Se
usará durante todo el día, aunque a intervalos poco frecuentes.

• Si ese programa depende de algunos procesos internos pesados, o tiene


muchos trabajos artísticos en sus formularios, tarde o temprano su uso de
memoria va a crecer, dejando menos memoria para otros procesos más
frecuentes, aumentando la actividad de paginación y, finalmente,
desacelerándose el ordenador.

• Siga leyendo para descubrir cómo diseñar su programa de tal manera


que mantenga su uso de memoria bajo control ...

• Nota: si desea saber cuánta memoria está usando su aplicación


actualmente, y como no puede pedirle al usuario de la aplicación que mire
al Administrador de tareas, aquí hay una función Delphi personalizada:
CurrentMemoryUsage

• 02 de 06

• Cuándo crear formularios en sus aplicaciones Delphi

• delphi
program DPR file auto-create formularios de listado.

• Digamos que va a diseñar un programa con un formulario principal y dos


formularios adicionales (modales). Normalmente, dependiendo de su
versión de Delphi, Delphi insertará los formularios en la unidad de
proyecto (archivo DPR) e incluirá una línea para crear todos los formularios
al inicio de la aplicación (Application.CreateForm (...)
• Las líneas incluidas en la unidad del proyecto están diseñadas por Delphi, y
son ideales para personas que no están familiarizadas con Delphi o que
recién están comenzando a usarlo. Es conveniente y útil. También significa
que TODOS los formularios se crearán cuando el programa se inicie y NO
cuando se necesiten.

• Dependiendo de qué se trata su proyecto y la funcionalidad que ha


implementado, un formulario puede usar mucha memoria, por lo que los
formularios (o, en general, los objetos) solo deben crearse cuando sea
necesario y destruirse (liberarse) tan pronto como ya no sean
necesarios. .

• Si "MainForm" es la forma principal de la aplicación, debe ser la única forma


creada al inicio en el ejemplo anterior.

• Tanto "DialogForm" como "OccasionalForm" deben eliminarse de la lista de


"Creación automática de formularios" y moverse a la lista "Formularios
disponibles".

• Lea "Cómo hacer que los formularios funcionen: un manual" para obtener
una explicación más detallada y cómo especificar qué formularios se crean.

• Lea el " TForm.Create (AOwner) ... AOwner?!? " Para saber quién debe ser
el propietario del formulario (más: qué es el "propietario").

• Ahora, cuando sepa cuándo se deben crear formularios y quién debería ser
el Propietario, pasemos a cómo vigilar el consumo de memoria ...

• 03 de 06

• Recortar la memoria asignada: no tan tonto como lo hace Windows


• Tenga en cuenta que la estrategia descrita aquí se basa en la suposición de
que el programa en cuestión es un programa tipo "captura" en tiempo real.
Sin embargo, puede adaptarse fácilmente para procesos de tipo por lotes.

• Windows y la asignación de memoria


• Windows tiene una forma bastante ineficiente de asignar memoria a sus
procesos. Asigna memoria en bloques significativamente grandes.

• Delphi ha intentado minimizar esto y tiene su propia arquitectura de


administración de memoria que usa bloques mucho más pequeños, pero
esto es virtualmente inútil en el entorno de Windows porque la asignación
de memoria finalmente recae en el sistema operativo.

• Una vez que Windows ha asignado un bloque de memoria a un proceso, y


ese proceso libera el 99.9% de la memoria, Windows aún percibirá que todo
el bloque estará en uso, incluso si solo se está utilizando un byte del
bloque. La buena noticia es que Windows proporciona un mecanismo para
solucionar este problema. El shell nos proporciona una API
llamada SetProcessWorkingSetSize . Aquí está la firma:

• > SetProcessWorkingSetSize (hProcess: HANDLE; MinimumWorkingSetSize: DWORD;


MaximumWorkingSetSize: DWORD);

• Veamos la función SetProcessWorkingSetSize ...

• 04 de 06

• La función All Mighty SetProcessWorkingSetSize API


• Por definición, la función SetProcessWorkingSetSize establece los tamaños
de conjunto de trabajo mínimo y máximo para el proceso especificado.

• Esta API está diseñada para permitir la configuración de bajo nivel de los
límites mínimos y máximos de memoria para el espacio de uso de memoria
del proceso. Sin embargo, tiene un pequeño capricho incorporado que es
muy afortunado.

• Si los valores mínimos y máximos están configurados en $ FFFFFFFF, la


API recortará temporalmente el tamaño del conjunto a 0, lo intercambiará
de la memoria e inmediatamente cuando rebote en la memoria RAM, tendrá
la cantidad mínima de memoria asignada. a eso (todo esto ocurre en un par
de nanosegundos, por lo que para el usuario debe ser imperceptible).

• Además, una llamada a esta API solo se realizará a intervalos


determinados, no de forma continua, por lo que no debería haber ningún
impacto en el rendimiento.

• Tenemos que tener cuidado con un par de cosas.

• En primer lugar, el identificador al que se hace referencia aquí es el


manejador de proceso NO el manejador de formularios principal (por lo que
no podemos simplemente usar "Manejar" o " Auto. Manejar").

• Lo segundo es que no podemos llamar a esta API indescriminadamente,


debemos intentar llamarla cuando el programa se considere inactivo. La
razón de esto es que no queremos recortar la memoria en el momento
exacto en que algo del procesamiento (un clic de botón, una tecla
presionada, un control de control, etc.) está a punto de suceder o está
sucediendo. Si eso está permitido, corremos un serio riesgo de incurrir en
violaciones de acceso.

• Siga leyendo para aprender cómo y cuándo llamar a la función


SetProcessWorkingSetSize desde nuestro código Delphi ...

• 05 de 06
• Recortar el uso de memoria en la fuerza

La función SetProcessWorkingSetSize API está diseñada para permitir la


configuración de bajo nivel de los límites mínimos y máximos de memoria para el
espacio de uso de memoria del proceso.

Aquí hay una función de Delphi de muestra que ajusta la llamada a


SetProcessWorkingSetSize:

> procedimiento TrimAppMemorySize; var MainHandle: Thandle; comience


a probar MainHandle: = OpenProcess (PROCESS_ALL_ACCESS, false,
GetCurrentProcessID); SetProcessWorkingSetSize (MainHandle, $ FFFFFFFF, $
FFFFFFFF); CloseHandle (MainHandle); excepto
el final ; Application.ProcessMessages; fin ;
¡Estupendo! Ahora tenemos el mecanismo para recortar el uso de la memoria . El
único otro obstáculo es decidir CUÁNDO llamarlo. He visto bastantes VCL de
terceros y estrategias para obtener el sistema, la aplicación y todo tipo de tiempo
de inactividad. Al final, decidí quedarme con algo simple.

En el caso de un programa de tipo captura / consulta, decidí que sería seguro


asumir que el programa está inactivo si se minimiza, o si no ha habido pulsaciones
de teclas o clics del mouse durante un cierto período. Hasta ahora, esto parece
haber funcionado bastante bien, ya que estamos tratando de evitar conflictos con
algo que solo va a tomar una fracción de segundo.

Esta es una forma de realizar un seguimiento programático del tiempo de


inactividad de un usuario.

Siga leyendo para descubrir cómo he usado el evento OnMessage de


TApplicationEvent para llamar a mi TrimAppMemorySize ...

06 de 06

TApplicationEvents OnMessage + a Timer: = TrimAppMemorySize AHORA

En este código lo tenemos establecido de esta manera:

Cree una variable global para contener la última cuenta de marca registrada EN
EL FORMULARIO PRINCIPAL. En cualquier momento que haya actividad en el
teclado o el mouse, registre el conteo de ticks.

Ahora, compruebe periódicamente el último conteo de ticks contra "Ahora" y si la


diferencia entre los dos es mayor que el período considerado inactivo seguro,
recorte la memoria.

> var LastTick: DWORD;


Coloque un componente ApplicationEvents en el formulario principal. En su
controlador de eventos OnMessage ingrese el siguiente código:

> procedure TMainForm.ApplicationEvents1Message ( var Msg:


tagMSG; var Handled: Boolean); begin case Msg.message of WM_RBUTTONDOWN,
WM_RBUTTONDBLCLK, WM_LBUTTONDOWN, WM_LBUTTONDBLCLK,
WM_KEYDOWN: LastTick: = GetTickCount; fin ; fin ;
Ahora decida después de qué período de tiempo considerará que el programa
está inactivo. Decidimos dos minutos en mi caso, pero puede elegir el período que
desee dependiendo de las circunstancias.

Coloque un temporizador en el formulario principal. Establezca su intervalo en


30000 (30 segundos) y en su evento "OnTimer" ponga la siguiente instrucción de
una línea:

> procedimiento TMainForm.Timer1Timer (Sender:


TObject); begin if (((GetTickCount - LastTick) / 1000)> 120) o (Self.WindowState =
wsMinimized) luego TrimAppMemorySize; fin ;

Adaptación para procesos largos o programas por lotes

Adaptar este método para largos tiempos de procesamiento o procesos por lotes
es bastante simple. Normalmente tendrá una buena idea de dónde comenzará un
proceso largo (por ejemplo, el comienzo de una lectura de bucle a través de
millones de registros de la base de datos) y dónde finalizará (final del bucle de
lectura de la base de datos).

Simplemente desactive el temporizador al inicio del proceso y vuelva a habilitarlo


al final del proceso.

Clase Delphi con código fuente


• by Zarko Gajic

Use Windows Hooks en sus aplicaciones Delphi


Código enviado por Jens Borrisholt. Texto de Zarko Gajic.

Por Jens: Hooks, he visto a mucha gente tratando de hacer una solución limpia
para enganchar mensajes en una aplicación. Así que decidí hace algún tiempo
implementar ganchos como clase, con buenos eventos y cosas :)

Hook.pas hace posible asignar un puntero de método a un puntero de


procedimiento (con alguna ayuda del ensamblador).
Por ejemplo: si quiere capturar TODAS las pulsaciones de teclas en su aplicación,
simplemente declare una instancia de TKeyboardHook, asigne un controlador de
eventos para OnPreExecute o OnPostExecute, o ambos.

Configure KeyboadHook active (KeyboardHook.Active: = True) y estará fuera de


servicio.

En Windows Hooks
Esto es lo que la guía API de Windows tiene que decir en los ganchos:

Un gancho es un punto en el mecanismo de manejo de mensajes del sistema


donde una aplicación puede instalar una subrutina para monitorear el tráfico de
mensajes en el sistema y procesar ciertos tipos de mensajes antes de que lleguen
al procedimiento de ventana de destino.

En pocas palabras, un gancho es una función que puede crear como parte de un
dll o su aplicación para controlar los 'sucesos' dentro del sistema operativo
Windows.

La idea es escribir una función que se llame cada vez que ocurra un determinado
evento en Windows, por ejemplo, cuando un usuario presiona una tecla en el
teclado o mueve el mouse.

Para una introducción más profunda a los ganchos, eche un vistazo a Qué son los
ganchos de Windows y cómo usarlos dentro de una aplicación Delphi .

El mecanismo de enganche depende de los mensajes de Windows y las funciones


de devolución de llamada .

Tipos de ganchos
Diferentes tipos de ganchos permiten que una aplicación monitoree un aspecto diferente
del mecanismo de manejo de mensajes del sistema.

Por ejemplo:
Puede usar el gancho WH_KEYBOARD para supervisar la entrada del teclado
publicada en una cola de mensajes;
Puede usar el gancho WH_MOUSE para monitorear la entrada del mouse
publicada en una cola de mensajes;
Puede realizar un procedimiento de enlace WH_SHELL cuando la aplicación de
shell está a punto de activarse y cuando se crea o destruye una ventana de nivel
superior.

Hooks.pas
La unidad hooks.pas define varios tipos de gancho:

▪ TCBTook - llamado antes de activar, crear, destruir, minimizar, maximizar, mover o


dimensionar una ventana; antes de completar un comando del sistema; antes de
eliminar un evento de mouse o teclado de la cola de mensajes del sistema; antes de
configurar el foco de entrada; o antes de sincronizar con la cola de mensajes del
sistema.
▪ TDebugHook - llamado antes de llamar a los procedimientos de enlace asociados con
cualquier otro enlace en el sistema
▪ TGetMessageHook: permite que una aplicación supervise los mensajes que van a
devolver la función GetMessage o PeekMessage.
▪ TJournalPlaybackHook: permite que una aplicación inserte mensajes en la cola de
mensajes del sistema.
▪ TJournalRecordHook - le permite monitorear y registrar eventos de entrada (para
grabar una secuencia de eventos de mouse y teclado para reproducir más tarde
utilizando el gancho WH_JOURNALPLAYBACK).
▪ TKeyboardHook: permite que una aplicación controle el tráfico de mensajes para
mensajes WM_KEYDOWN y WM_KEYUP.
▪ TMouseHook: le permite controlar los mensajes del mouse a punto de ser devueltos
por la función GetMessage o PeekMessage.
▪ TLowLevelKeyboardHook: le permite supervisar eventos de entrada de teclado a punto
de publicarse en una cola de entrada de subprocesos.
▪ TLowLevelMouseHook: le permite controlar los eventos de entrada del mouse a punto
de publicarse en una cola de entrada de subprocesos.
Ejemplo de TKeyboardHook
Para mostrarle cómo usar hooks.pas, aquí hay una sección de la aplicación demo de hook
de teclado:

Descargue la aplicación hooks.pas + demo

> usa ganchos, .... var KeyboardHook: TKeyboardHook; .... // Procedimiento del controlador
de eventos OnCreate de MainForm TMainForm.FormCreate (Sender:
TObject); begin KeyboardHook: = TKeyboardHook.Create; KeyboardHook.OnPreExecute: =
KeyboardHookPREExecute; KeyboardHook.Active: = True; fin ; // maneja
el procedimiento OnPREExecute de KeyboardHook TMainForm.KeyboardHookPREExecute
(Hook: THook; var Hookmsg: THookMsg); var clave: Word; begin // Aquí puede elegir si
desea devolver // el trazo de tecla a la aplicación o no Hookmsg.Result: = IfThen
(cbEatKeyStrokes.Checked, 1, 0); Clave: = Hookmsg.WPARAM; Leyenda: = Char
(clave); fin ; Listo, listo, gancho :)
Enganche el mouse para capturar eventos
fuera de una aplicación
• by Zarko Gajic
• Aprenda a seguir la actividad del mouse incluso cuando su aplicación no
esté activa, se encuentre en la bandeja o no tenga ninguna UI .

• Al instalar un enganche para el mouse en todo el sistema (o global) puede


controlar lo que el usuario está haciendo con el mouse y actuar en
consecuencia.

• ¿Qué es un gancho y cómo funciona?


• En resumen, un gancho es una función (de devolución de llamada ) que
puede crear como parte de una DLL ( biblioteca de enlace dinámico ) o su
aplicación para monitorear los 'sucesos' dentro del sistema operativo
Windows.


Hay 2 tipos de ganchos: global y local. Un gancho local monitorea cosas
que suceden solo para un programa específico (o hilo). Un gancho global
supervisa todo el sistema (todos los hilos).

• El artículo " Una introducción a los procedimientos de enlace ", establece


que para crear un enlace global necesita 2 proyectos, 1 para crear el
archivo ejecutable y 1 para crear un archivo DLL que contenga el
procedimiento de enlace.
Al trabajar con los ganchos del teclado de Delphi se explica cómo
interceptar la entrada del teclado para los controles que no pueden recibir el
foco de entrada (como TImage).

• Enganchar el mouse
• Por diseño, el movimiento del mouse está restringido por el tamaño de la
pantalla de su escritorio (incluida la barra de tareas de Windows). Cuando
mueva el mouse hacia el borde izquierdo / derecho / superior / inferior, el
mouse se "detendrá", como se espera (si no tiene más de un monitor).

• Esta es una idea para el gancho del mouse en todo el sistema: si, por
ejemplo, desea mover el mouse hacia el lado derecho de la pantalla cuando
se mueve hacia el borde izquierdo (y lo "toca"), puede escribir un gancho de
ratón global para reposicionar el puntero del mouse.

• Empiezas creando un proyecto de biblioteca de enlaces dinámicos. La DLL


debería exportar dos métodos: "HookMouse" y "UnHookMouse".
• El procedimiento HookMouse llama a la API SetWindowsHookEx pasando
el "WH_MOUSE" para el primer parámetro, instalando así un procedimiento
de enlace que supervisa los mensajes del mouse. Uno de los parámetros
de SetWindowsHookEx es su función de devolución de llamada que
Windows llamará cuando haya un mensaje del mouse para procesar:

• SetWindowsHookEx (WH_MOUSE, @HookProc, HInstance, 0);

• El último parámetro (valor = 0) en SetWindowsHookEx define que estamos


registrando un gancho global.

• El HookProc analiza los mensajes relacionados con el mouse y envía un


mensaje personalizado ("MouseHookMessage") a nuestro proyecto de
prueba:

• > función HookProc (nCode: Entero; MsgID: WParam; Datos: LParam):


LResult; stdcall; var mousePoint: TPoint; notifyTestForm: boolean; MouseDirection:
TMouseDirection; begin mousePoint: = PMouseHookStruct (Data) ^.
pt; notifyTestForm: = falso; if (mousePoint.X =
0) entonces comience Windows.SetCursorPos (-2 + Screen.Width,
mousePoint.y); notifyTestForm: = verdadero; MouseDirection: =
mdRight; fin ; .... if notifyTestForm entonces comienza PostMessage (FindWindow
('TMainHookTestForm', nil), MouseHookMessage, MsgID, Integer
(MouseDirection)); fin ; Resultado: = CallNextHookEx (Hook, nCode, MsgID,
Data); fin ;

• Nota 1: Lea los archivos de Ayuda de Win32 SDK para obtener información
sobre el registro PMouseHookStruct y la firma de la función HookProc.

• Nota 2: una función de enlace no necesita enviar nada a ninguna parte: la


llamada de PostMessage se usa solo para indicar que la DLL se puede
comunicar con el mundo "externo".

• Gancho del mouse "Listener"


• El mensaje "MouseHookMessage" se publica en su proyecto de prueba, un
formulario llamado "TMainHookTestForm". Anulará el método WndProc
para obtener el mensaje y actuar según sea necesario:

• > procedimiento TMainHookTestForm.WndProc ( var Message:


TMessage); comenzar heredado WndProc (Mensaje); si Message.Msg =
HookCommon.MouseHookMessage, entonces comience // implementación
encontrada en el código acompañante Signal (TMouseDirection
(Message.LParam)); fin ; fin ;
• Por supuesto, cuando se crea el formulario (OnCreate) se llama al
procedimiento HookMouse desde el DLL, cuando se cierra (OnDestroy) se
llama al procedimiento UnHookMouse.

• Nota: Los ganchos tienden a ralentizar el sistema porque aumentan la


cantidad de procesamiento que el sistema debe realizar para cada
mensaje. Debe instalar un gancho solo cuando sea necesario y eliminarlo lo
antes posible

Cargar una DLL desde un recurso


directamente desde la memoria en
aplicaciones Delphi
• by Zarko Gajic

Utilice DLL de recursos (RES) sin almacenarlo primero en el disco duro


Idea del artículo por Mark E. Moss

El artículo sobre cómo almacenar una DLL dentro de un archivo exe del programa
Delphi como recurso explica cómo enviar una DLL con su archivo ejecutable de la
aplicación Delphi como recurso.

Las bibliotecas de enlaces dinámicos contienen código o recursos compartibles,


brindan la capacidad para que múltiples aplicaciones compartan una sola copia de
una rutina (o recurso) que tienen en común.

Usando archivos de recursos (.RES) , puede incrustar (y usar) archivos de sonido,


videoclips, animaciones y, en general, cualquier tipo de archivo binario en un
ejecutable Delphi.

Cargando archivos DLL desde la memoria


Recientemente, recibí un correo electrónico de Mark E. Moss en el que me preguntaba si
una DLL almacenada en una RES puede usarse sin guardarla primero en el sistema de
archivos (disco duro) .

De acuerdo con el artículo Cargando una DLL de memoria por Joachim Bauch,
esto es posible.

He aquí cómo Joachim analiza el problema: las funciones predeterminadas de la


API de Windows para cargar bibliotecas externas en un programa (LoadLibrary,
LoadLibraryEx) solo funcionan con archivos en el sistema de archivos. Por lo
tanto, es imposible cargar una DLL desde la memoria. Pero a veces, necesita
exactamente esta funcionalidad (p. Ej., No desea distribuir muchos archivos o
desea dificultar el desmontaje). Las soluciones comunes para estos problemas
consisten en escribir primero la DLL en un archivo temporal e importarla desde
allí. Cuando el programa finaliza, el archivo temporal se elimina.

El código en el artículo mencionado es C ++, el siguiente paso fue convertirlo a


Delphi. Afortunadamente, esto ya lo ha hecho Martin Offenwanger (el autor de
DSPlayer).

El Módulo de memoria de Martin Offenwanger es una versión extendida de Delphi


(y también de Lazarus) compatible del C ++ Memory Module 0.0.1 de Joachim
Bauch. El paquete zip incluye el código fuente completo de Delphi del
MemoyModule (BTMemoryModule.pas). Además, se incluye un Delphi y una
muestra para demostrar cómo usarlo.

Carga de archivos DLL de recursos de memoria


Lo que quedaba por implementar es tomar la DLL de un archivo RES y luego llamar a sus
procedimientos y funciones.

Si una DLL de demostración se almacena como un recurso usando el archivo RC:

DemoDLL RCDATA DemoDLL.dll

para cargarlo desde el recurso, se puede usar el siguiente código:

var
ms: TMemoryStream;
rs: TResourceStream;
empezar
si 0 <> FindResource (hInstance, 'DemoDLL', RT_RCDATA), entonces
empezar
rs: = TResourceStream.Create (hInstance, 'DemoDLL', RT_RCDATA);
ms: = TMemoryStream.Create;
tratar
ms.LoadFromStream (rs);

ms.Position: = 0;
m_DllDataSize: = ms.Size;
mp_DllData: = GetMemory (m_DllDataSize);

ms.Read (mp_DllData ^, m_DllDataSize);


finalmente
ms.Free;
rs.Free;
fin ;
fin ;
fin ;

Luego, cuando tenga la DLL cargada desde un recurso en la memoria, puede llamar a sus
procedimientos:

var
btMM: PBTMemoryModule;
empezar
btMM: = BTMemoryLoadLibary (mp_DllData, m_DllDataSize);
tratar
si btMM = nil luego Abort;
@m_TestCallstd: = BTMemoryGetProcAddress (btMM, 'TestCallstd');
si @m_TestCallstd = nil luego Abort;
m_TestCallstd ('Esta es una llamada de memoria Dll!');
excepto
Showmessage ('Se ha producido un error al cargar el dll:' + BTMemoryGetLastError);
fin ;
si está asignado (btMM), entonces BTMemoryFreeLibrary (btMM);
fin;

Eso es. Aquí hay una receta rápida:

1. Tener / Crear una DLL


2. Almacene el archivo DLL en un archivo RES
3. Tener la implementación de BTMemoryModule .
4. Tome la DLL del recurso y cárguela directamente en la memoria.
5. Use los métodos de BTMemoryModule para ejecutar el procedimiento desde la DLL en
la memoria.
BTMemoryLoadLibary en Delphi 2009, 2010, ...
Poco después de publicar este artículo, he recibido un correo electrónico de Jason Penny:
"El BTMemoryModule.pas enlazado no funciona con Delphi 2009 (y asumiría Delphi 2010
también).
Encontré una versión similar del archivo BTMemoryModule.pas hace un tiempo, e hice
cambios para que funcione con (al menos) Delphi 2006, 2007 y 2009. Mi
BTMemoryModule.pas actualizado, y un proyecto de muestra, están en BTMemoryLoadLibary
para Delphi> = 2009 "
Cómo enviar información (cadena,
imagen, registro) entre dos aplicaciones
• by Zarko Gajic
• Hay muchas situaciones en las que debe permitir que se comuniquen dos
aplicaciones. Si no quiere meterse con la comunicación de TCP y
sockets (porque ambas aplicaciones se ejecutan en la misma máquina),
puede * simplemente * enviar (y recibir correctamente) un mensaje especial
de Windows: WM_COPYDATA .

• Dado que manejar mensajes de Windows en Delphi es simple, emitir una


llamada API de SendMessage junto con el WM_CopyData llenado con los
datos que se enviarán es bastante sencillo.

• WM_CopyData y TCopyDataStruct
• El mensaje WM_COPYDATA le permite enviar datos de una aplicación a
otra. La aplicación receptora recibe los datos en
un registro TCopyDataStruct. TCopyDataStruct se define en la unidad
Windows.pas y envuelve la estructura COPYDATASTRUCT que contiene
los datos que se pasarán.

• Aquí está la declaración y la descripción del registro TCopyDataStruct:

• > escriba TCopyDataStruct = registro empaquetado dwData: DWORD; // hasta 32


bits de datos para pasar a la aplicación receptora cbData: DWORD; // el tamaño, en
bytes, de los datos apuntados por el miembro lpData lpData: Pointer; // Apunta a los
datos que se pasarán a la aplicación receptora. Este miembro puede ser nil. fin ;

• Enviar una cadena sobre WM_CopyData


• Para que una aplicación "Remitente" envíe datos a "Receptor",
CopyDataStruct se debe completar y pasar usando la función Enviar
mensaje. A continuación, se indica cómo enviar un valor de cadena sobre
WM_CopyData:

• > procedimiento TSenderMainForm.SendString (); var stringToSend:


cadena; copyDataStruct: TCopyDataStruct; begin stringToSend: = 'Acerca de la
Programación Delphi'; copyDataStruct.dwData: = 0; // usarlo para identificar el
contenido del mensaje copyDataStruct.cbData: = 1 + Length
(stringToSend); copyDataStruct.lpData: = PChar (stringToSend); SendData
(copyDataStruct); fin ;

• La función personalizada SendData localiza el receptor utilizando la llamada


API FindWindow:
• > procedimiento TSenderMainForm.SendData ( const copyDataStruct:
TCopyDataStruct); var receiverHandle: Thandle; res: entero; begin receiverHandle: =
FindWindow (PChar ('TReceiverMainForm'), PChar
('ReceiverMainForm')); if receiverHandle = 0 entonces comience ShowMessage
('Receptor de datos de copia NO encontrado!'); Salida; fin ; res: = SendMessage
(receiverHandle, WM_COPYDATA, Integer (Handle), Integer (@copyDataStruct)); fin ;

• En el código anterior, se encontró la aplicación "Receptor" utilizando la


llamada FindWindow API pasando el nombre de la clase del formulario
principal ("TReceiverMainForm") y el título de la ventana
("ReceiverMainForm").

• Nota: SendMessage devuelve un valor entero asignado por el código que


manejó el mensaje WM_CopyData.

• Manejando WM_CopyData - Recibiendo una cadena


• La aplicación "Receiver" maneja el mensaje WM_CopyData como en:

• > escriba TReceiverMainForm = clase


(TForm) procedimiento privado WMCopyData ( var Msg:
TWMCopyData); mensaje WM_COPYDATA; ... implementación ... procedimiento T
ReceiverMainForm.WMCopyData (var Msg: TWMCopyData); var s: cadena; begin s: =
PChar (Msg.CopyDataStruct.lpData); // Enviar algo atrás msg.Result: = 2006; fin ;

• El registro TWMCopyData se declara como:

• > TWMCopyData = packed record Msg: Cardinal; De: HWND; // Manejar de la


ventana que pasó los datos CopyDataStruct: PCopyDataStruct; // datos
pasados Resultado: Entero largo; // Úselo para enviar un valor al final "Remitente" ;

• ¿Enviando cadena, registro personalizado o una imagen?


• El código fuente que lo acompaña demuestra cómo enviar una cadena, un
registro (tipo de datos complejo) e incluso gráficos (mapa de bits) a otra
aplicación.

• Si no puede esperar la descarga, aquí le mostramos cómo enviar un gráfico


TBitmap:

• > procedimiento TSenderMainForm.SendImage (); var ms: TMemoryStream; bmp:


TBitmap; copyDataStruct: TCopyDataStruct; begin ms: =
TMemoryStream.Create; prueba bmp: =
self.GetFormImage; prueba bmp.SaveToStream
(ms); finalmente bmp.Free; fin ; copyDataStruct.dwData: = Integer (cdtImage); //
identifica los datos copyDataStruct.cbData: = ms.Size; copyDataStruct.lpData: =
ms.Memory; SendData (copyDataStruct); finalmente ms.Free; fin ; fin ;
• Y cómo recibirlo:

• > procedimiento TReceiverMainForm.HandleCopyDataImage (copyDataStruct:


PCopyDataStruct); var ms: TMemoryStream; begin ms: =
TMemoryStream.Create; intente ms.Write (copyDataStruct.lpData ^,
copyDataStruct.cbData); ms.Position: =
0; receivedImage.Picture.Bitmap.LoadFromStream
(ms); finalmente ms.Free; fin ; fin ;

Una introducción al trabajo con el


Registro de Windows
• by Zarko Gajic

El Registro es simplemente una base de datos que una aplicación puede usar
para almacenar y recuperar información de configuración (el último tamaño y
posición de la ventana, las opciones e información del usuario o cualquier otra
información de configuración). El registro también contiene información sobre
Windows (95/98 / NT) y sobre su configuración de Windows.

La "base de datos" del Registro se almacena como un archivo binario. Para


encontrarlo, ejecute regedit.exe (utilidad de editor de registro de Windows) en su
directorio de Windows.

Verá que la información en el Registro está organizada de manera similar a


Windows Explorer. Podemos usar regedit para ver información del registro,
cambiarla o agregarle información. Es obvio que las modificaciones de la base de
datos del registro podrían provocar un bloqueo del sistema (por supuesto, si no
sabe lo que está haciendo).

INI vs. Registro

Probablemente es muy conocido que en los días de Windows 3.xx los archivos INI
eran una forma popular de almacenar información de aplicaciones y otras
configuraciones configurables por el usuario. El aspecto más aterrador de los
archivos INI es que son solo archivos de texto que el usuario puede editar
fácilmente (cambiarlos o incluso eliminarlos).
En Windows de 32 bits, Microsoft recomienda usar Registry para almacenar el tipo
de información que normalmente colocaría en los archivos INI (es menos probable
que los usuarios alteren las entradas de registro).
Delphi brinda soporte completo para cambiar entradas en el Registro del sistema
de Windows: a través de la clase TRegIniFile (la misma interfaz básica que la
clase TIniFile para usuarios de archivos INI con Delphi 1.0) y la clase TRegistry
(contenedor de bajo nivel para el registro de Windows y funciones que operan en
el registro).

Consejo simple: escribir en el Registro

Como se mencionó anteriormente en este artículo, las operaciones básicas de


registro (mediante la manipulación de código) leen información del registro y
escriben información en el registro.
La siguiente pieza de código cambiará el fondo de pantalla de Windows y
desactivará el protector de pantalla con la clase TRegistry.

Antes de que podamos usar TRegistry, tenemos que agregar la unidad de registro
a la cláusula uses en la parte superior del código fuente.

~~~~~~~~~~~~~~~~~~~~~~~~~
usa registro;
procedure TForm1.FormCreate (Sender: TObject);
var
reg: TRegistry;
empezar
reg: = TRegistry.Create;
con reg comenzar
tratar
si OpenKey ('\ Control Panel \ desktop', False) entonces comienza
// cambiar el fondo de pantalla y colocarlo en mosaico
reg.WriteString ('Fondo de pantalla', 'c: \ windows \ CIRCLES.bmp');
reg.WriteString ('TileWallpaper', '1');
// desactivar el protector de pantalla // ('0' = desactivar, '1' = habilitar)
reg.WriteString ('ScreenSaveActive', '0');
// actualiza los cambios inmediatamente
SystemParametersInfo (SPI_SETDESKWALLPAPER, 0, nil,
SPIF_SENDWININICHANGE);
SystemParametersInfo (SPI_SETSCREENSAVEACTIVE, 0, nil,
SPIF_SENDWININICHANGE);
fin
finalmente
reg.Free;
fin;
fin;
fin;
~~~~~~~~~~~~~~~~~~~~~~~~~

Esas dos líneas de código que comienzan con SystemParametersInfo ... obligan a
Windows a actualizar inmediatamente el fondo de pantalla y la información del
protector de pantalla. Cuando ejecuta su aplicación, verá que el mapa de bits del
fondo de pantalla de Windows cambia a la imagen Circles.bmp (esto es, si tiene
una imagen de circles.bmp en su directorio de Windows).
Nota: su protector de pantalla ahora está desactivado.

Más muestras de uso de TRegistry

▪ Enumeración y reproducción de sonidos del sistema del código Delphi


▪ Crear un administrador de inicio de Windows

▪ Usando la clave RunOnce


▪ Cómo almacenar un TDateTime en el Registro
▪ Registro de monitoreo
▪ Restricciones del sistema con registro
▪ Trabajando con archivos INI

Edición de archivos INI de Delphi


• by Zarko Gajic
• Trabajar con archivos de configuración de configuración (.INI)

• Los archivos INI son archivos de texto utilizados para almacenar los datos
de configuración de una aplicación.

• Aunque Windows recomienda usar el Registro de Windows para almacenar


datos de configuración específicos de la aplicación, en muchos casos,
encontrará que los archivos INI proporcionan una manera más rápida para
que el programa acceda a su configuración. Windows incluso usa archivos
INI; desktop.ini y boot.ini son solo dos ejemplos.

• Un uso simple de los archivos INI como mecanismo de ahorro de estado


sería guardar el tamaño y la ubicación de un formulario si desea que un
formulario vuelva a aparecer en su posición anterior.

• En lugar de buscar en toda una base de datos de información para


encontrar el tamaño o la ubicación, se usa un archivo INI en su lugar.

• El formato de archivo INI


• El archivo de configuración de inicialización o configuración (.INI) es un
archivo de texto con un límite de 64 KB dividido en secciones, cada una con
cero o más claves. Cada clave contiene cero o más valores.

• Aquí hay un ejemplo:

• > [Nombre de sección] nombre clave1 = valor; comentario nombre clave2 = valor
• Los nombres de las secciones están entre corchetes y deben comenzar
al principio de una línea. La sección y los nombres de las teclas no
distinguen entre mayúsculas y minúsculas (el caso no importa) y no pueden
contener caracteres espaciados. El nombre de la tecla es seguido por un
signo igual ("="), opcionalmente rodeado por espacios de caracteres, que
son ignorados.

• Si la misma sección aparece más de una vez en el mismo archivo, o si la


misma tecla aparece más de una vez en la misma sección, prevalecerá la
última ocurrencia.

• Una clave puede contener cadena , entero o valor booleano .

• Delphi IDE usa el formato de archivo INI en muchos casos. Por ejemplo,
los archivos .DSK (configuración de escritorio) utilizan el formato INI.

• Clase TIniFile
• Delphi proporciona la clase TIniFile , declarada en la unidad inifiles.pas ,
con métodos para almacenar y recuperar valores de archivos INI.

• Antes de trabajar con los métodos TIniFile, debe crear una instancia de la
clase:

• > usa inifiles; ... var IniFile: TIniFile; begin IniFile: = TIniFile.Create ('myapp.ini');

• El código anterior crea un objeto IniFile y asigna 'myapp.ini' a la única


propiedad de la clase, la propiedad FileName, utilizada para especificar el
nombre del archivo INI que va a utilizar.

• El código como está escrito arriba busca el archivo myapp.ini en el


directorio \ Windows . Una mejor forma de almacenar los datos de la
aplicación está en la carpeta de la aplicación: simplemente especifique la
ruta completa del archivo para el método Create :

• > // coloca el INI en la carpeta de la aplicación, // deja que tenga el nombre de la


aplicación // y 'ini' para la extensión: iniFile: = TIniFile.Create (ChangeFileExt
(Application.ExeName, '. ini'));

• Lectura de INI
• La clase TIniFile tiene varios métodos de "lectura". ReadString lee un valor
de cadena de una clave, ReadInteger. ReadFloat y similares se usan para
leer un número de una clave. Todos los métodos de "lectura" tienen un
valor predeterminado que se puede usar si la entrada no existe.

• Por ejemplo, ReadString se declara como:

• > function ReadString ( const Section, Ident, Default: String): String; anular ;
• Escribir a INI
• El TIniFile tiene un método de "escritura" correspondiente para cada
método de "lectura". Son WriteString, WriteBool, WriteInteger, etc.

• Por ejemplo, si queremos que un programa recuerde el nombre de la última


persona que lo usó, cuándo era y cuáles eran las coordenadas principales,
podríamos establecer una sección llamada Usuarios , una palabra clave
llamada Última , Fecha para rastrear la información y una sección
llamada Ubicación con las teclas Arriba , Izquierda , Ancho y Alto .

• > project1.ini [User] Last = Zarko Gajic Fecha = 29/01/2009 [Placement] Top = 20
Left = 35 Width = 500 Height = 340

• Tenga en cuenta que la clave llamada Last contiene un valor de


cadena, Date contiene un valor de TDateTime y todas las claves de la
sección Placement tienen un valor entero.

• El evento OnCreate del formulario principal es el lugar perfecto para


almacenar el código necesario para acceder a los valores en el archivo de
inicialización de la aplicación:

• > procedimiento TMainForm.FormCreate (Sender: TObject); var appINI:


TIniFile; LastUser: cadena; LastDate: TDateTime; begin appINI: = TIniFile.Create
(ChangeFileExt (Application.ExeName, '. ini')); intente // si ningún último usuario
devuelve una cadena vacía LastUser: = appINI.ReadString ('User', 'Last', ''); // si
ninguna fecha pasada devuelve la fecha de hoy LastDate: = appINI.ReadDate
('Usuario', 'Fecha', Fecha); // muestra el mensaje ShowMessage ('Este programa fue
utilizado previamente por' + LastUser + 'en' + DateToStr (LastDate)); Superior: =
appINI.ReadInteger ('Colocación', 'Superior', Superior); Izquierda: =
appINI.ReadInteger ('Colocación', 'Izquierda', Izquierda); Ancho: = appINI.ReadInteger
('Colocación', 'Ancho', Ancho); Altura: = appINI.ReadInteger ('Colocación', 'Altura',
Altura); finalmente appINI.Free; fin ; fin ;

• El evento OnClose de la forma principal es ideal para la parte Guardar


INI del proyecto.

• > procedure TMainForm.FormClose (Sender: TObject; var Acción:


TCloseAction); var appINI: TIniFile; begin appINI: = TIniFile.Create (ChangeFileExt
(Application.ExeName, '. ini')); prueba appINI.WriteString ('Usuario', 'Último', 'Zarko
Gajic'); appINI.WriteDate ('Usuario', 'Fecha', Fecha); con appINI,
MainForm comienza WriteInteger ('Colocación', 'Superior', Superior); WriteInteger
('Colocación', 'Izquierda', Izquierda); WriteInteger ('Colocación', 'Ancho',
Ancho); WriteInteger ('Colocación', 'Altura',
Altura); fin ; finalmente appIni.Free; fin ; fin ;
• Secciones INI
• EraseSection borra una sección completa de un archivo
INI. ReadSection y ReadSections llenan un objeto TStringList con los
nombres de todas las secciones (y nombres de clave) en el archivo INI.

• Limitaciones y desventajas de INI


• La clase TIniFile usa la API de Windows que impone un límite de 64 KB en
archivos INI. Si necesita almacenar más de 64 KB de datos, debe usar
TMemIniFile.

• Otro problema puede surgir si tiene una sección con más de 8 K de valor.
Una forma de resolver el problema es escribir su propia versión del método
ReadSection.

Entender las operaciones de arrastrar y


soltar
• by Zarko Gajic
• Incluyendo ejemplos de código fuente

• Para "arrastrar y soltar" se debe mantener presionado el botón del mouse


mientras se mueve el mouse, y luego suelte el botón para soltar el objeto.
Delphi facilita el programa de arrastrar y soltar en las aplicaciones.

• Puedes arrastrar y soltar desde / hacia donde quieras, como de una forma a
otra, o desde Windows Explorer a tu aplicación.

• Ejemplo de arrastrar y soltar


• Inicie un nuevo proyecto y coloque un control de imagen en un formulario.

• Use el Inspector de Objetos para cargar una imagen (propiedad de Imagen)


y luego configure la propiedad DragMode en dmManual .

• Crearemos un programa que permitirá mover un tiempo de ejecución de


control de TI utilizando la técnica de arrastrar y soltar.

• DragMode
• Los componentes permiten dos tipos de arrastre: automático y manual.
Delphi usa la propiedad DragMode para controlar cuándo el usuario puede
arrastrar el control.

• El valor predeterminado de esta propiedad es dmManual, lo que significa


que no se permite arrastrar componentes por la aplicación, excepto en
circunstancias especiales, para lo cual tenemos que escribir el código
apropiado.
• Independientemente de la configuración de la propiedad DragMode, el
componente se moverá solo si se escribe el código correcto para
reposicionarlo.

• OnDragDrop
• El evento que reconoce arrastrar y soltar se llama evento OnDragDrop. Lo
usamos para especificar lo que queremos que suceda cuando el usuario
suelta un objeto. Por lo tanto, si queremos mover un componente (imagen)
a una nueva ubicación en un formulario, tenemos que escribir el código
para el controlador de eventos OnDragDrop del formulario.

• > procedure TForm1.FormDragDrop (Sender, Fuente: TObject; X, Y:


Integer); comience si la Fuente es TImage luego comience TImage (Fuente). Left: =
X; TImage (Fuente) .Top: = Y; fin ; fin ;

• El parámetro de origen del evento OnDragDrop es el objeto que se


descarta. El tipo del parámetro fuente es TObject. Para acceder a sus
propiedades, debemos convertirlo al tipo de componente correcto, que en
este ejemplo es TImage.

• Aceptar
• Tenemos que usar el evento OnDragOver del formulario para indicar que el
formulario puede aceptar el control de TImage que queremos colocar sobre
él. Aunque el parámetro Aceptar se establece de forma predeterminada en
Verdadero, si no se proporciona un controlador de eventos OnDragOver, el
control rechaza el objeto arrastrado (como si el parámetro Aceptar se
hubiera cambiado a Falso).

• > procedure TForm1.FormDragOver (Remitente, Origen: TObject; X, Y: Entero;


Estado: TDragState; var Aceptar: Booleano); comenzar Aceptar: = (La
fuente es TImage); fin ;

• Ejecute su proyecto e intente arrastrar y soltar su imagen. Observe que la


imagen permanece visible en su ubicación original mientras se mueve el
puntero del mouse de arrastre. No podemos usar el procedimiento
OnDragDrop para hacer que el componente sea invisible mientras se lleva
a cabo el arrastre porque este procedimiento se invoca solo después de
que el usuario suelta el objeto (si es que lo hace).

• Drag Cursor
• Si desea cambiar la imagen del cursor presentada cuando se arrastra el
control, use la propiedad DragCursor. Los valores posibles para la
propiedad DragCursor son los mismos que para la propiedad Cursor.

• Puede utilizar un curso de animación o lo que quiera, como un archivo de


imagen BMP o un archivo de cursor CUR.
• BeginDrag
• Si DragMode es dmAutomatic, el arrastre comienza automáticamente
cuando presionamos el botón del mouse con el cursor en el control.

• Si ha dejado el valor de la propiedad DragMode de TImage en su valor


predeterminado de dmManual, debe usar los métodos BeginDrag / EndDrag
para permitir el arrastre del componente.

• Una forma más común de arrastrar y soltar es establecer DragMode en


dmManual e iniciar el arrastre manipulando los eventos del mouse.

• Ahora, usaremos la combinación de teclas Ctrl + MouseDown para permitir


que se lleve a cabo el arrastre. Establezca TImage's DragMode en
dmManual y escriba el controlador de eventos MouseDown de la siguiente
manera:

• > procedure TForm1.Image1MouseDown (Sender: TObject; Botón: TMouseButton;


Shift: TShiftState; X, Y: Integer); comience si ssCtrl en Shift luego Image1.BeginDrag
(True); fin ;

• BeginDrag toma un parámetro booleano. Si pasamos True (como en este


código), el arrastre comienza inmediatamente; si es False, no comienza
hasta que movemos el mouse una corta distancia.

• Recuerde que requiere la tecla Ctrl.

Almacenar datos de usuario y aplicación


en la ubicación correcta
• by Zarko Gajic

Obtener ruta de carpeta conocida utilizando Delphi

Cuando necesite almacenar algún contenido relacionado con su aplicación Delphi


en el disco duro del usuario, debe encargarse de la separación del estado de los
datos del usuario, la configuración del usuario y la configuración de la
computadora.

Por ejemplo, la carpeta "Datos de la aplicación" en Windows se debe usar para


almacenar documentos específicos de la aplicación, como archivos INI , estado de
la aplicación, archivos temporales o similares.

Nunca debe usar rutas codificadas a ubicaciones específicas, como "c: \ Archivos
de programa", ya que puede no funcionar en otras versiones de Windows porque
la ubicación de las carpetas y directorios puede cambiar con diferentes versiones
de Windows.

La función API de Windows SHGetFolderPath

SHGetFolderPath está disponible en la unidad SHFolder . SHGetFolderPath


recupera la ruta completa de una carpeta conocida identificada.

Aquí hay una función de envoltura personalizada alrededor de la API


SHGetFolderPath para ayudarlo a obtener cualquiera de las carpetas estándar
para todos o para el usuario de Windows actualmente conectado.

> usa SHFolder; función GetSpecialFolderPath (carpeta:


entero): cadena ; const SHGFP_TYPE_CURRENT =
0; var path: array [0..MAX_PATH] de char; comience si SUCEDE (SHGetFolderPath
(0, carpeta, 0, SHGFP_TYPE_CURRENT, @ ruta [0])) luego Resultado: =
ruta else Resultado: = ''; fin ;
Aquí hay un ejemplo del uso de la función SHGetFolderPath:

▪ Coloque un TRadioButtonGroup (nombre: "RadioGroup1") en un formulario


▪ Coloque un TLabel (nombre: "Etiqueta1") en un formulario
▪ Agregue 5 artículos al grupo de radio:
1. "[Usuario actual] \ Mis documentos"
2. "Todos los usuarios \ Datos de aplicación"
3. "[Específico del usuario] \ Datos de aplicación"
4. "Archivos de programa"
5. "Todos los usuarios \ Documentos"

▪ Maneje el evento OnClick de RadioGroup como:


Nota: "[Usuario actual]" es el nombre del usuario de Windows actualmente
conectado.

> // RadioGroup1 procedimiento OnClick TForm1.RadioGroup1Click (Sender:


TObject); índice var : entero; especialFolder:
entero; comience si RadioGroup1.ItemIndex = -1 y luego Salir; índice: =
RadioGroup1.ItemIndex; índice de caso de // [Usuario actual] \ Mis documentos 0:
especial Carpeta: = CSIDL_PERSONAL; // Todos los usuarios \ Datos de aplicación 1:
especialFolder: = CSIDL_COMMON_APPDATA; // [User Specific] \ Application Data 2:
specialFolder: = CSIDL_LOCAL_APPDATA; // Archivos de programa 3: specialFolder: =
CSIDL_PROGRAM_FILES; // Todos los usuarios \ Documents 4: specialFolder: =
CSIDL_COMMON_DOCUMENTS; fin ; Label1.Caption: = GetSpecialFolderPath
(specialFolder); fin ;
Nota: SHGetFolderPath es un superconjunto de SHGetSpecialFolderPath.

No debe almacenar datos específicos de la aplicación (como archivos temporales,


preferencias del usuario, archivos de configuración de la aplicación, etc.) en la
carpeta Mis documentos. En su lugar, use un archivo específico de la aplicación
que se encuentre en una carpeta de Datos de aplicación válida.

Agregue siempre una subcarpeta a la ruta que SHGetFolderPath devuelve. Use la


siguiente convención: "\ Application Data \ Company Name \ Product Name \
Product Version".

Crear una base de datos usando el


"Archivo de" archivos tipados de Delphi
• by Zarko Gajic
• Comprender los archivos tipados

• Simplemente ponga un archivo es una secuencia binaria de algún tipo.


En Delphi , hay tres clases de archivos : tipeado, texto y sin tipo . Los
archivos tipados son archivos que contienen datos de un tipo particular,
como Doble, Entero o tipo de registro personalizado previamente definido.
Los archivos de texto contienen caracteres ASCII legibles. Los archivos sin
tipo se utilizan cuando queremos imponer la menor estructura posible en un
archivo.

• Archivos mecanografiados
• Mientras que los archivos de texto consisten en líneas terminadas con una
combinación CR / LF ( # 13 # 10 ), los archivos tipeados consisten en
datos tomados de un tipo particular de estructura de datos .

• Por ejemplo, la siguiente declaración crea un tipo de registro llamado


TMember y una matriz de variables de registro de TMember.

• > escriba TMember


= registro Nombre: cadena [50]; eMail: cadena [30]; Publicaciones:
LongInt; fin ; var Miembros: array [1..50] de TMember;

• Antes de que podamos escribir la información en el disco, tenemos que


declarar una variable de un tipo de archivo. La siguiente línea de código
declara una variable de archivo F.

• > var F: archivo de TMember;


• Nota: Para crear un archivo tipado en Delphi, usamos la siguiente sintaxis :

• var SomeTypedFile: archivo de SomeType

• El tipo de base (SomeType) para un archivo puede ser de tipo escalar


(como Double), un tipo de matriz o un tipo de registro. No debería ser
cadena larga, matriz dinámica, clase, objeto o puntero.

• Para comenzar a trabajar con archivos de Delphi, tenemos que vincular un


archivo en un disco a una variable de archivo en nuestro programa. Para
crear este enlace debemos usar el procedimiento AssignFile para asociar
un archivo en un disco con una variable de archivo.

• > AssignFile (F, 'Members.dat')

• Una vez establecida la asociación con un archivo externo, la variable de


archivo F debe estar 'abierta' para prepararla para lectura y / o escritura.
Llamamos al procedimiento Restablecer para abrir un archivo existente o
Reescribir para crear un nuevo archivo. Cuando un programa completa el
procesamiento de un archivo, el archivo debe cerrarse usando el
procedimiento CloseFile.

• Después de cerrar un archivo, se actualiza su archivo externo asociado. La


variable de archivo puede asociarse con otro archivo externo.

• En general, siempre debemos usar el manejo de excepciones ; muchos


errores pueden surgir al trabajar con archivos. Por ejemplo: si llamamos a
CloseFile para un archivo que ya está cerrado, Delphi informa un error de E
/ S. Por otro lado, si tratamos de cerrar un archivo pero aún no hemos
llamado a AssignFile, los resultados son impredecibles.

• Escribir en un archivo
• Supongamos que hemos llenado un conjunto de miembros de Delphi con
sus nombres, correos electrónicos y número de publicaciones, y queremos
almacenar esta información en un archivo en el disco. La siguiente pieza de
código hará el trabajo:

• > var F: archivo de TMember; i: entero; comenzar AssignFile (F,


'members.dat'); Reescribir (F); intente con j: = 1 a 50 do Write (F, Members
[j]); finalmente CloseFile (F); fin ; fin ;

• Leer de un archivo
• Para recuperar toda la información del archivo 'members.dat', usaríamos el
siguiente código :
• > var Miembro: TMember F: archivo de TMember; comenzar AssignFile (F,
'members.dat'); Restablecer (F); intente mientras no Eof (F) comiencen a leer (F,
miembro); {DoSomethingWithMember;} end ; finalmente CloseFile (F); fin ; fin ;

• Nota: Eof es la función de comprobación EndOfFile. Utilizamos esta función


para asegurarnos de que no estamos tratando de leer más allá del final del
archivo (más allá del último registro almacenado).

• Buscando y posicionando
• Normalmente, se accede a los archivos secuencialmente. Cuando se lee un
archivo usando el procedimiento estándar Leído o escrito usando el
procedimiento estándar Escribir, la posición actual del archivo se mueve al
siguiente componente de archivo ordenado numéricamente (próximo
registro). También se puede acceder aleatoriamente a los archivos tipeados
a través del procedimiento estándar Buscar, que mueve la posición actual
del archivo a un componente específico. Las
funciones FilePos y FileSize se pueden usar para determinar la posición
actual del archivo y el tamaño actual del archivo.

• > {volver al principio - el primer registro} Buscar (F, 0); {ir al registro 5 °} Buscar (F,
5); {Saltar al final - "después" del último registro} Buscar (F, FileSize (F));

• Cambiar y actualizar
• Acaba de aprender a escribir y leer todo el conjunto de miembros, pero
¿qué sucede si lo único que desea hacer es buscar al 10º miembro y
cambiar el correo electrónico? El siguiente procedimiento hace
exactamente eso:

• > procedimiento ChangeEMail ( const RecN:


integer; const NewEMail: string ); var DummyMember: TMember; begin {assign,
open, exception handling block} Buscar (F, RecN); Lee (F,
DummyMember); DummyMember.Email: = NewEMail; {leer mueve al siguiente
registro, tenemos que volver al registro original, luego escribir} Buscar (F,
RecN); Escribir (F, DummyMember); {archivo cerrado} final ;

• Completando la tarea
• Eso es todo, ahora tienes todo lo que necesitas para llevar a cabo tu tarea.
Puede escribir la información de los miembros en el disco, puede leerla e
incluso puede cambiar algunos de los datos (correo electrónico, por
ejemplo) en el "medio" del archivo.

• Lo importante es que este archivo no es un archivo ASCII , así es como se


ve en el Bloc de notas (solo un registro):

• > .Delphi Guide g Ò5 · ¿ì. 5.. B V.Lƒ, "¨.delphi@aboutguide.comÏ .. ç.ç.ï ..


El lado oscuro de
Application.ProcessMessages en
aplicaciones Delphi
• by Zarko Gajic

Usando Application.ProcessMessages? ¿Deberías Reconsiderar?


Artículo presentado por Marcus Junglas

Al programar un controlador de eventos en Delphi (como el evento OnClick de un


TButton), llega el momento en que su aplicación necesita estar ocupada por un
tiempo, por ejemplo, el código necesita escribir un archivo grande o comprimir
algunos datos.

Si lo hace, notará que su aplicación parece estar bloqueada . Tu formulario ya


no se puede mover y los botones no muestran signos de vida.

Parece estar estrellado.

La razón es que una aplicación Delpi tiene un solo subproceso. El código que está
escribiendo representa solo un grupo de procedimientos que son llamados por el
hilo principal de Delphi cada vez que ocurre un evento. El resto del tiempo, el hilo
principal es el manejo de los mensajes del sistema y otras cosas como funciones
de manejo de formularios y componentes.

Por lo tanto, si no finaliza el manejo de su evento realizando un trabajo


prolongado, evitará que la aplicación maneje esos mensajes.

Una solución común para este tipo de problemas es llamar a


"Application.ProcessMessages". "Aplicación" es un objeto global de la clase
TApplication.

Application.Processmessages maneja todos los mensajes en espera, como


movimientos de ventanas, clics de botones, etc. Se usa comúnmente como una
solución simple para mantener su aplicación "funcionando".

Lamentablemente, el mecanismo detrás de "ProcessMessages" tiene sus propias


características, ¡lo que puede causar una gran confusión!

¿Qué es ProcessMessages?
PprocessMessages maneja todos los mensajes del sistema en espera en la cola
de mensajes de las aplicaciones. Windows usa mensajes para "hablar" a todas las
aplicaciones en ejecución. La interacción del usuario se lleva a cabo a través de
mensajes y "ProcessMessages" los maneja.

Si el mouse está bajando en un TButton, por ejemplo, ProgressMessages hace


todo lo que debería suceder en este evento, como volver a pintar el botón a un
estado "presionado" y, por supuesto, una llamada al procedimiento de manejo
OnClick () si asignado uno

Ese es el problema: cualquier llamada a ProcessMessages podría contener una


llamada recursiva a cualquier controlador de eventos nuevamente. Aquí hay un
ejemplo:

Use el siguiente código para el controlador OnClick even de un botón ("trabajo").


El for-statement simula un trabajo de procesamiento largo con algunas llamadas a
ProcessMessages de vez en cuando.

Esto se simplifica para una mejor legibilidad:

> {en MyForm:} WorkLevel: entero; {OnCreate:} WorkLevel: =


0; procedimiento TForm1.WorkBtnClick (Sender: TObject); var ciclo:
entero; begin inc (WorkLevel); para el ciclo: = 1 a 5 comienzan Memo1.Lines.Add ('-
Work' + IntToStr (WorkLevel) + ', Cycle' + IntToStr
(cycle); Application.ProcessMessages; sleep (1000); // o algún otro trabajo end ;
Memo1.Lines.Add ('Work' + IntToStr (WorkLevel) + 'ended.'); dec (WorkLevel); end ;
SIN "Mensaje de proceso", las siguientes líneas se escriben en la nota, si se
presionó el botón DOS VECES en poco tiempo:

> - Trabajo 1, Ciclo 1 - Trabajo 1, Ciclo 2 - Trabajo 1, Ciclo 3 - Trabajo 1, Ciclo 4 -


Trabajo 1, Ciclo 5 Trabajo 1 finalizado. - Trabajo 1, Ciclo 1 - Trabajo 1, Ciclo 2 -
Trabajo 1, Ciclo 3 - Trabajo 1, Ciclo 4 - Trabajo 1, Ciclo 5 Trabajo 1 finalizado.
Mientras el procedimiento está ocupado, el formulario no muestra ninguna
reacción, pero el segundo clic fue puesto en la cola de mensajes por Windows.

Justo después de que el "OnClick" haya terminado, se volverá a llamar.

INCLUYENDO "ProcessMessages", el resultado puede ser muy diferente:

> - Trabajo 1, Ciclo 1 - Trabajo 1, Ciclo 2 - Trabajo 1, Ciclo 3 - Trabajo 2, Ciclo 1 -


Trabajo 2, Ciclo 2 - Trabajo 2, Ciclo 3 - Trabajo 2, Ciclo 4 - Trabajo 2, Ciclo 5 Trabajo
2 terminó. - Trabajo 1, Ciclo 4 - Trabajo 1, Ciclo 5 Trabajo 1 terminado.
Esta vez, el formulario parece estar funcionando nuevamente y acepta cualquier
interacción del usuario. De modo que el botón se presiona a la mitad durante su
primera función de "trabajador", que se manejará instantáneamente. Todos los
eventos entrantes se manejan como cualquier otra llamada a función.
En teoría, durante cada llamada a "ProgressMessages", CUALQUIER cantidad de
clics y mensajes del usuario puede suceder "en su lugar".

¡Así que ten cuidado con tu código!

Ejemplo diferente (¡en pseudocódigo simple!):

> procedimiento OnClickFileWrite (); var miarchivo: = TFileStream; begin myfile: =


TFileStream.create ('myOutput.txt'); try while BytesReady> 0 do begin myfile.Write
(DataBlock); dec (BytesReady, sizeof (DataBlock)); DataBlock [2]: = # 13; {línea de
prueba 1} Application.ProcessMessages; DataBlock [2]: = # 13; {test line
2} end ; finalmente myfile.free; fin ; fin ;
Esta función escribe una gran cantidad de datos e intenta "desbloquear" la
aplicación mediante el uso de "mensajes de proceso" cada vez que se escribe un
bloque de datos.

Si el usuario vuelve a hacer clic en el botón, se ejecutará el mismo código


mientras se está escribiendo el archivo. Entonces, el archivo no se puede abrir
una segunda vez y el procedimiento falla.

Tal vez su aplicación recuperará algunos errores, como liberar los búferes.

Como posible resultado, se liberará "Datablock" y el primer código generará


"repentinamente" una "Infracción de acceso" cuando acceda a él. En este caso: la
línea de prueba 1 funcionará, la línea de prueba 2 se bloqueará.

La mejor manera:

Para hacerlo más fácil, puede configurar todo el Formulario "enabled: = false", que
bloquea todas las entradas de los usuarios, pero NO lo muestra al usuario (todos
los botones no están atenuados).

Una forma mejor sería configurar todos los botones en "deshabilitado", pero esto
podría ser complejo si desea mantener un botón "Cancelar" por ejemplo. También
necesita revisar todos los componentes para deshabilitarlos y, cuando vuelvan a
habilitarse, debe verificar si quedan algunos en estado deshabilitado.

Podría desactivar un contenedor de controles secundarios cuando la propiedad


Habilitada cambie .

Como sugiere el nombre de clase "TNotifyEvent", solo debe usarse para


reacciones a corto plazo al evento. Para el código que consume tiempo, la mejor
manera es en mi humilde opinión de poner todo el código "lento" en un hilo propio.

En cuanto a los problemas con "Mensajes de precesión" y / o la habilitación y


deshabilitación de componentes, el uso de un segundo subproceso parece no ser
demasiado complicado en absoluto.
Recuerde que incluso las líneas de código simples y rápidas pueden bloquearse
durante segundos, por ejemplo, la apertura de un archivo en una unidad de disco
podría tener que esperar hasta que la unidad se haya agotado. No se ve muy bien
si su aplicación parece bloquearse porque el disco es demasiado lento.

Eso es. La próxima vez que agregue "Application.ProcessMessages", piense dos


veces;)

Comprender los tipos genéricos en Delphi


• by Zarko Gajic
• Aprenda a parametrizar sus registros y tipos

• Los genéricos, una poderosa adición a Delphi, se introdujeron en Delphi


2009 como una nueva característica de langage. Los genéricos o tipos
genéricos (también conocidos como tipos parametrizados ) le permiten
definir clases que no definen específicamente el tipo de ciertos miembros
de datos.

• Como ejemplo, en lugar de utilizar el tipo TObjectList para tener una lista de
cualquier tipo de objeto, desde Delphi 2009, la
unidad Generics.Collections define TObjectList con más caracteres.

• Aquí hay una lista de artículos que explican los tipos genéricos en Delphi
con ejemplos de uso:

• Qué y por qué y cómo en Generics in Delphi


• Uso de nuevos estilos y arquitecturas de codificación Delphi
El tipo genérico se puede usar como el tipo de un campo (como lo hice en
el ejemplo anterior), como el tipo de una propiedad, como el tipo de un
parámetro o el valor de retorno de una función y más.

• Genéricos con Delphi 2009 Win32


Los genéricos a veces se llaman parámetros genéricos, un nombre que
permite introducirlos algo mejor. A diferencia de un parámetro de función
(argumento), que tiene un valor, un parámetro genérico es un tipo. Y
parametriza una clase, una interfaz, un registro o, con menos frecuencia, un
método ... Con, como beneficio adicional, rutinas anónimas y referencias de
rutina

• Tutorial de Delphi Generics


Delphi tList, tStringList, tObjectlist o tCollection se pueden usar para
construir contenedores especializados, pero requieren un tipo de
fundido. Con Generics, se evita el lanzamiento y el compilador puede
detectar los errores de tipo antes.
• Usando Generics en Delphi
Una vez que haya escrito una clase usando parámetros de tipo genéricos
(genéricos), puede usar esa clase con cualquier tipo y el tipo que elija usar
con cualquier uso dado de esa clase reemplaza los tipos genéricos que
utilizó cuando creó la clase.

• Interfaces genéricas en Delphi


La mayoría de los ejemplos que he visto de Generics en Delphi usan clases
que contienen un tipo genérico. Sin embargo, mientras trabajaba en un
proyecto personal, decidí que quería una interfaz que incluyera un tipo
genérico.

• Ejemplo de tipo genérico simple


• A continuación se explica cómo definir una clase genérica simple:
• tipo
TGenericContainer = clase
Valor: T;
fin ;

• Con la siguiente definición, aquí se explica cómo usar un contenedor genérico


entero y de cadena:
• var
genericInt: TGenericContainer ;
genericStr: TGenericContainer ;
empezar
genericInt: = TGenericContainer .Create;
genericInt.Value: = 2009; // solo enteros
genericInt.Free;

genericStr: = TGenericContainer . Crear;


genericStr.Value: = 'Delphi Generics'; // solo cadenas
genericStr.Free;
fin ;
• El ejemplo anterior solo araña la superficie de usar Generics en Delphi (aunque no
explica nada, ¡pero los artículos anteriores lo tienen todo lo que quiere saber!).

• Para mí, los genéricos fueron la razón para pasar de Delphi 7/2007 a Delphi
2009 (y más reciente).

Colocación de aplicaciones Delphi en la


bandeja del sistema
• by Zarko Gajic
• El lugar perfecto para programas que se ejecutan sin interacción del usuario

• Eche un vistazo a su barra de tareas. Ver el área donde se encuentra el


tiempo? ¿Hay algún otro ícono allí? El lugar se llama Bandeja del sistema
de Windows. ¿Le gustaría colocar el icono de su aplicación Delphi allí?
¿Desea que el icono esté animado o refleje el estado de su aplicación?

• Esto sería útil para programas que se dejan funcionando durante largos
periodos de tiempo sin interacción del usuario (tareas en segundo plano
que normalmente se ejecutan en su PC todo el día).

• Lo que puede hacer es hacer que sus aplicaciones Delphi se vean


minimizadas a la Bandeja (en lugar de a la Barra de tareas, directamente al
botón de Inicio de Windows) colocando un ícono en la bandeja y al mismo
tiempo haciendo que su (s) formulario (s) sea invisible.

• Vamos a la bandeja
• Afortunadamente, crear una aplicación que se ejecute en la bandeja del
sistema es bastante fácil: solo se necesita una función (API),
Shell_NotifyIcon, para realizar la tarea.

• La función se define en la unidad ShellAPI y requiere dos parámetros. El


primero es un indicador que indica si el icono se agrega, modifica o elimina,
y el segundo es un puntero a una estructura TNotifyIconData que contiene
la información sobre el ícono. Eso incluye el manejo del icono para mostrar,
el texto para mostrar como información sobre herramientas cuando el
mouse está sobre el ícono, el control de la ventana que recibirá los
mensajes del ícono y el tipo de mensaje que el ícono enviará a esta
ventana.

• Primero, en la sección privada de su formulario principal, ponga la línea:


TrayIconData: TNotifyIconData;

• tipo TMainForm = clase (TForm) procedimiento FormCreate (Sender:


TObject); private TrayIconData: TNotifyIconData; {Declaraciones
privadas} public {Public declarations} end ;

• Luego, en el método OnCreate de su formulario principal, inicialice la


estructura de datos TrayIconData y llame a la función Shell_NotifyIcon:

• con TrayIconData do empiece cbSize: = SizeOf (TrayIconData); Wnd: = Handle; uID:


= 0; uFlags: = NIF_MESSAGE + NIF_ICON + NIF_TIP; uCallbackMessage: =
WM_ICONTRAY; hIcon: = Application.Icon.Handle; StrPCopy (szTip,
Application.Title); fin ; Shell_NotifyIcon (NIM_ADD, @TrayIconData);
• El parámetro Wnd de la estructura TrayIconData apunta a la ventana que
recibe mensajes de notificación asociados con un icono.

• El hIcon apunta al ícono que queremos agregar a la Bandeja, en este caso


se usa el ícono principal de Aplicaciones.
El szTip contiene el texto de la información sobre herramientas para
mostrar para el icono; en nuestro caso, el título de la aplicación. El szTip
puede contener hasta 64 caracteres.

El parámetro uFlags está configurado para indicarle al icono que procese


los mensajes de la aplicación, utilice el ícono de la aplicación y su
sugerencia. El uCallbackMessage apunta al identificador de mensaje
definido por la aplicación. El sistema usa el identificador especificado para
los mensajes de notificación que envía a la ventana identificada por Wnd
cada vez que se produce un evento de mouse en el rectángulo delimitador
del icono. Este parámetro se establece en la constante WM_ICONTRAY
definida en la sección de interfaz de la unidad forms y es igual a:
WM_USER + 1;

• Agregue el icono a la bandeja llamando a la función API de


Shell_NotifyIcon.

• El primer parámetro "NIM_ADD" agrega un ícono al área de la Bandeja. Los


otros dos valores posibles, NIM_DELETE y NIM_MODIFY se utilizan para
eliminar o modificar un icono en la Bandeja; veremos cómo más adelante
en este artículo. El segundo parámetro que enviamos a Shell_NotifyIcon es
la estructura inicializada de TrayIconData.

• Tomar uno...
• Si ejecuta su proyecto ahora, verá un ícono cerca del reloj en la bandeja.
Tenga en cuenta tres cosas.

• 1) Primero, no ocurre nada cuando hace clic (o hace cualquier otra cosa
con el mouse) en el ícono colocado en la Bandeja; aún no hemos creado un
procedimiento (manejador de mensajes).
2) Segundo, hay un botón en la barra de tareas (obviamente no lo
queremos allí).
3) En tercer lugar, cuando cierra su aplicación, el icono permanece en la
Bandeja.

• Toma dos...
• Vamos a resolver esto al revés. Para que el icono se elimine de la Bandeja
cuando salga de la aplicación, debe llamar a Shell_NotifyIcon nuevamente,
pero con NIM_DELETE como primer parámetro.

• Lo hace en el controlador de eventos OnDestroy para el formulario


principal.
• procedimiento TMainForm.FormDestroy (Sender:
TObject); comenzar Shell_NotifyIcon (NIM_DELETE, @TrayIconData); fin ;

• Para ocultar la aplicación (botón de la aplicación) desde la barra de tareas


utilizaremos un truco simple. En el código fuente de Proyectos, agregue la
siguiente línea: Application.ShowMainForm: = False; antes de
Application.CreateForm (TMainForm, MainForm); Por ejemplo, que se vea
así:

• ... begin Application.Initialize; Application.ShowMainForm: = Falso;


Application.CreateForm (TMainForm, MainForm); Aplicación.Ejecutar; fin.

• Y finalmente, para que nuestro icono de Bandeja responda a los eventos


del mouse, debemos crear un procedimiento de manejo de mensajes.
Primero declaramos un procedimiento de manejo de mensajes en la parte
pública de la declaración de formulario: procedure TrayMessage (var Msg:
TMessage); mensaje WM_ICONTRAY; En segundo lugar, la definición de
este procedimiento se ve así:

• procedure TMainForm.TrayMessage ( var Msg:


TMessage); begin case Msg.lParam of WM_LBUTTONDOWN: begin ShowMessage
('Botón izquierdo clic - ¡MOSTRAR el formulario!'); MainForm.Show; fin ;
WM_RBUTTONDOWN: begin ShowMessage ('botón derecho pulsado - vamos a
OCULTAR el formulario!'); MainForm.Hide; fin ; fin ; fin ;

• Este procedimiento está diseñado para manejar solo nuestro mensaje,


WM_ICONTRAY. Toma el valor LParam de la estructura del mensaje que
puede darnos el estado del mouse al activar el procedimiento. En aras de la
simplicidad, manejaremos solo el botón izquierdo del mouse hacia abajo
(WM_LBUTTONDOWN) y el botón derecho del mouse hacia abajo
(WM_RBUTTONDOWN).

• Cuando el botón izquierdo del mouse está en el ícono, mostramos el


formulario principal, cuando se presiona el botón derecho lo ocultamos. Por
supuesto, hay otros mensajes de entrada de mouse que puede manejar en
el procedimiento, como, botón arriba, botón doble clic, etc.

• Eso es. Rapido y Facil. A continuación, verá cómo animar el icono en la


bandeja y cómo hacer para que ese icono refleje el estado de su aplicación.
Aún más, verá cómo mostrar un menú emergente cerca del ícono.
Notificación de pérdida de memoria en
Delphi en la salida del programa
• by Zarko Gajic
• Todas las versiones de Delphi desde Delphi 2006 tienen un administrador
de memoria actualizado que es más rápido y con más funciones.

• Una de las mejores funciones del "nuevo" administrador de memoria


permite a las aplicaciones registrar (y eliminar el registro) las fugas de
memoria esperadas y, opcionalmente, informar pérdidas de memoria
inesperadas al apagar el programa.

• Al crear aplicaciones WIN32 con Delphi, es imprescindible asegurarse de


liberar todos los objetos (memoria) que crea dinámicamente.

• Se produce una pérdida de memoria (o recurso) cuando el programa pierde


la capacidad de liberar la memoria que consume.

• Informar pérdidas de memoria al apagar


• La detección e informe de fuga de memoria se establece en falso de forma
predeterminada. Para habilitarlo, debe establecer la variable global
ReportMemoryLeaksOnShutdown en TRUE.

• Cuando la aplicación se cierra, si hay pérdidas de memoria inesperadas, la


aplicación mostrará el cuadro de diálogo "Fuga de memoria inesperada".

• El mejor lugar para ReportMemoryLeaksOnShutdown sería en el archivo


de código fuente (dpr) del programa.

• > begin ReportMemoryLeaksOnShutdown: = DebugHook <> 0; // fuente


"por" Aplicación Delphi. Inicializar; Application.MainFormOnTaskbar: =
Verdadero; Application.CreateForm (TMainForm, MainForm); Aplicación.Ejecutar; fin

• Nota: una variable global DebugHook se usa arriba para asegurarse de que
las pérdidas de memoria se muestren cuando la aplicación se ejecuta en
modo de depuración, cuando ajusta F9 desde Delphi IDE.

• Test Drive: detección de fugas de memoria


• Tener ReportMemoryLeaksOnShutdown establecido en TRUE, agregue el
siguiente código en el controlador de eventos OnCreate del formulario
principal.

• > var sl: TStringList; begin sl: = TStringList.Create; sl.Add ('¡Fuga de memoria!'); fin ;

• Ejecute la aplicación en modo de depuración, salga de la aplicación;


debería ver el cuadro de diálogo de pérdida de memoria.
• Nota: Si está buscando una herramienta para detectar los errores de la
aplicación Delphi, como corrupción de memoria, pérdidas de memoria,
errores de asignación de memoria, errores de inicialización de variables,
conflictos de definición de variables, errores de puntero ... eche un vistazo
a madExcept y EurekaLog

Formateo de los valores de fecha y hora


para acceder a SQL en Delphi
• by Zarko Gajic
• ¿Alguna vez ha recibido el horrible "El objeto del parámetro está
incorrectamente definido. Se ha proporcionado información
incompleta o incoherente " Error JET? He aquí cómo rectificar la
situación.

• Cuando necesite crear una consulta SQL en una base de datos de Access
donde se usa un valor de fecha (o fecha y hora), debe asegurarse de
utilizar el formato correcto.

• Por ejemplo, en una consulta SQL: "SELECT * FROM TBL WHERE


DateField = '10 / 12/2008 '" desea obtener todos los registros de la tabla
denominada TBL donde un campo de fecha general DateField es igual a
10/12/2008.

• ¿Está clara la línea de arriba? ¿Es eso el 10 de diciembre o el 12 de


octubre? Afortunadamente, estamos bastante seguros de que el año en la
consulta es 2008.

• ¿Debe especificarse la fecha de la consulta como MM / DD / AAAA o DD /


MM / AAAA o quizás AAAAMMDD? ¿Y la configuración regional juega un
papel aquí?

• MS Access, Jet, formato de fecha y hora


• Al utilizar Access y JET ( controles dbGo - ADO Delphi ), el formato del SQL
para el campo de fecha debe * siempre * ser:

• > # YYYY-MM-DD #

• Cualquier otra cosa podría funcionar en pruebas limitadas pero a menudo


puede conducir a resultados inesperados o errores en la máquina del
usuario.

• Aquí hay una función Delphi personalizada que puede usar para formatear
un valor de fecha para la consulta de Access SQL.
• > función DateForSQL ( const date: TDate): cadena ; var y, m, d:
palabra; comenzar DecodeDate (date, y, m, d); resultado: = Formato ('#%. * d -%. * d
-%. * d #', [4, y, 2, m, 2, d]); fin ;

• Para "29 de enero de 1973" la función devolverá la cadena '# 1973-01-29


#'.

• ¿Acceder al formato de fecha y hora de SQL?


• En cuanto al formato de fecha y hora, el formato general es:

• > # aaaa-mm-dd HH: MM: SS #

• Esto es: # year-month-daySPACEhour: minute: second #

• Tan pronto como construya una cadena de fecha y hora válida para el SQL
usando el formato general anterior y lo intente usando cualquiera de los
componentes del conjunto de datos de Delphi como TADOQuery, recibirá el
horrible "El objeto del parámetro está definido incorrectamente. Se
proporcionó información incompleta o incoherente" en tiempo de ejecución !

• El problema con el formato anterior está en el carácter ":", ya que se usa


para parámetros en consultas Delphi parametrizadas. Como en "... WHERE
DateField =: dateValue" - aquí "dateValue" es un parámetro y ":" se usa
para marcarlo.

• Una forma de "corregir" el error es usar otro formato para fecha / hora
(reemplace ":" por "."):

• > # aaaa-mm-dd HH.MM.SS #

• Y aquí está una función Delphi personalizada para devolver una cadena de
un valor de fecha y hora que puede usar al construir consultas SQL para
Access donde necesita buscar un valor de fecha y hora:

• > función DateTimeForSQL ( const dateTime: TDateTime): cadena ; var y, m, d:


palabra; hora, min, sec, mseg: palabra; comenzar DecodeDate (dateTime, y, m,
d); DecodeTime (dateTime, hour, min, sec, msec); resultado: = Formato ('#%. * d -%. *
d -%. * d%. * d.%. * d.%. * d #', [4, y, 2, m, 2, d, 2, hora, 2, min, 2, sec]); fin ;

• ¡El formato se ve raro pero dará como resultado el valor de la cadena de


fecha y hora correctamente formateado para ser utilizado en consultas
SQL!

• Aquí hay una versión más corta que usa la rutina FormatDateTime:

• > función DateTimeForSQL ( const dateTime: TDateTime): cadena ; begin result: =


FormatDateTime ('# aaaa-mm-dd hh.nn.ss #', dateTime); fin ;
Imprimir documentos desde Delphi -
Imprimir PDF, DOC, XLS, HTML, RTF,
DOCX, TXT
• by Zarko Gajic

Imprima mediante programación cualquier tipo de documento utilizando Delphi y


ShellExecute

Si su aplicación Delphi necesita operar en varios tipos de archivos, una de las


tareas que podría tener para su aplicación es permitirle al usuario de la
aplicación imprimir un archivo, cualquiera que sea el tipo de archivo .

La mayoría de las aplicaciones orientadas a documentos, como MS Word, MS


Excel o Adobe "saben" cómo imprimir documentos que están "a cargo". Por
ejemplo, Word guarda el texto que escribe en documentos con extensión DOC.

Dado que Word (Microsoft) determina cuál es el contenido "en bruto" de un archivo
.DOC, sabe cómo imprimir archivos .DOC. Lo mismo se aplica a cualquier tipo de
archivo "conocido" que contenga cierta información imprimible.

¿Qué sucede si necesita imprimir varios tipos de documentos / archivos desde su


aplicación? ¿Puede saber cómo enviar el archivo a la impresora para que se
imprima correctamente? Supongo que la respuesta es no. Al menos no lo sé :)

Imprima cualquier tipo de documento (PDF, DOC, XLS, HTML, RTF, DOCX)
usando Delphi
Entonces, ¿cómo se imprime cualquier tipo de documento, utilizando programáticamente
el código Delphi?

Bueno, supongo que deberíamos "preguntarle" a Windows: qué aplicación sabe


cómo imprimir, por ejemplo, un archivo PDF. O mejor aún deberíamos decirle a
Windows: aquí hay un archivo PDF, envíelo a la aplicación asociada / a cargo de
imprimir archivos PDF.

Abra el Explorador de Windows, navegue a un directorio que contenga algunos


archivos imprimibles. Para la mayoría de los tipos de archivos en su sistema,
cuando hace clic derecho en un archivo en el Explorador de Windows, encontrará
el comando "Imprimir".

Al ejecutar el comando Imprimir shell, el archivo se enviará a la impresora


predeterminada.
Bueno, eso es exactamente lo que queremos: para un tipo de archivo, llame a un
método que envíe el archivo a la aplicación asociada para imprimir .

La función que buscamos es la función ShellExecute API.

ShellExecute: Print / PrintTo


En su forma más simple, ShellExecute le permite iniciar cualquier aplicación / abrir
cualquier archivo que esté instalado en la máquina del usuario.

Sin embargo, ShellExecute puede hacer mucho más.

ShellExecute se puede utilizar para iniciar la aplicación, abrir el Explorador de


Windows, iniciar una búsqueda que comienza en el directorio especificado, y lo
que más nos importa ahora: imprime el archivo especificado.

Especificar impresora para ShellExecute / Print


A continuación se explica cómo imprimir un archivo utilizando la función ShellExecute: >
ShellExecute (Handle, ' print ', PChar ('c: \ document.doc'), nil, nil, SW_HIDE); Tenga en
cuenta el segundo parámetro: "imprimir".

Con la llamada anterior, se enviará un documento "document.doc" en la raíz de la


unidad C a la impresora predeterminada de Windows.

ShellExecute siempre usa la impresora predeterminada para la acción "imprimir".

¿Qué sucede si necesita imprimir en una impresora diferente? ¿Qué sucede si


desea permitir que el usuario cambie la impresora?

El comando PrintTo Shell


Algunas aplicaciones admiten la acción 'printto'. PrintTo se puede utilizar para especificar
el nombre de la impresora utilizada para la acción de impresión. La impresora está
determinada por 3 parámetros: nombre de la impresora, nombre de la unidad y puerto.

Imprimir archivos mediante programación


Ok, suficiente teoría. Tiempo para un código real:

Antes de copiar y pegar: la variable global Impresora (tipo TPrinter) disponible en


todos los programas Delphi se puede usar para administrar cualquier impresión
realizada por una aplicación. La impresora se define en la unidad "impresoras",
ShellExecute se define en la unidad "shellapi".

1. Coloque un TComboBox en un formulario. Llámalo "cboPrinter". Establecer estilo en


csDropDownLidt
2. Coloque las dos líneas siguientes en el controlador uniforme OnCreate del
formulario: > // tenga impresoras disponibles en el cuadro
combinado cboPrinter.Items.Assign (printer.Printers); // preselecciona la impresora
predeterminada / activa cboPrinter.ItemIndex: = printer.PrinterIndex;
Ahora, aquí está la función que puede usar para imprimir cualquier tipo de documento
en una impresora específica : > usa shellapi, impresoras; procedimiento PrintDocument
( const documentToPrint: string ); var printCommand: cadena ; printerInfo:
cadena; Dispositivo, Controlador, Puerto: array [0..255] de Char; hDeviceMode:
THandle; comience si Printer.PrinterIndex =
cboPrinter.ItemIndex luego comience printCommand: = 'print'; printerInfo: = ''; end else
begin printCommand: = 'printto'; Printer.PrinterIndex: =
cboPrinter.ItemIndex; Printer.GetPrinter (Dispositivo, Controlador, Puerto,
hDeviceMode); printerInfo: = Formato ('"% s" "% s" "% s"', [Dispositivo, Controlador,
Puerto]); fin ; ShellExecute (Application.Handle, PChar (printCommand), PChar
(documentToPrint), PChar (printerInfo), nil , SW_HIDE); fin ; Nota: si la impresora
seleccionada es la predeterminada, la función utiliza la acción "imprimir". Si la impresora
seleccionada no es la predeterminada, la función utiliza el método "printo".
Tenga en cuenta, también: algunos tipos de documentos NO tienen una aplicación
asociada para imprimir. Algunos no tienen la acción "printto" especificada.

Aquí se explica cómo cambiar la impresora predeterminada de Windows desde el


código Delphi

Rutinas de fecha / hora - Programación


Delphi
• by Zarko Gajic
• Compara dos valores de TDateTime (devuelve "menos", "igual" o
"mayor"). Ignora la parte de tiempo si ambos valores "caen" en el mismo
día.

• Función CompareDateTime
• Compara dos valores de TDateTime (devuelve "menos", "igual" o "mayor").

• Declaración:
tipo TValueRelationship = -1..1
función CompareDateTime ( const ADate, BDate: TDateTime):
TValueRelationship

• Descripción:
Compara dos valores de TDateTime (devuelve "menos", "igual" o "mayor").

• TValueRelationship representa la relación entre dos valores. Cada uno de


los tres valores de TValueRelationship tiene una constante simbólica "me
gusta":
-1 [LessThanValue] El primer valor es menor que el segundo valor.
0 [EqualsValue] Los dos valores son iguales.
1 [GreaterThanValue] El primer valor es mayor que el segundo valor.

CompareDate resultados en:

• LessThanValue si ADate es anterior a BDate.


EqualsValue si las partes de fecha y hora de ADate y BDate son las
mismas
GreaterThanValue si ADate es posterior a BDate.

• Ejemplo:

• var ThisMoment, FutureMoment: TDateTime; ThisMoment: = Now; FutureMoment:


= IncDay (ThisMoment, 6); // agrega 6 días // CompareDateTime (ThisMoment,
FutureMoment) devuelve LessThanValue (-1) // CompareDateTime (FutureMoment,
ThisMoment) devuelve GreaterThanValue (1)

• Función CompareTime
• Compara dos valores de TDateTime (devuelve "menos", "igual" o
"mayor"). Ignora la parte Fecha si ambos valores ocurren al mismo tiempo.

• Declaración:
tipo TValueRelationship = -1..1
función CompareDate ( const ADate, BDate: TDateTime):
TValueRelationship

• Descripción:
Compara dos valores de TDateTime (devuelve "menos", "igual" o "mayor").
Ignora la parte Tiempo si ambos valores ocurren al mismo tiempo.

• TValueRelationship representa la relación entre dos valores.

• Cada uno de los tres valores de TValueRelationship tiene una constante


simbólica "me gusta":
-1 [LessThanValue] El primer valor es menor que el segundo valor.
0 [EqualsValue] Los dos valores son iguales.
1 [GreaterThanValue] El primer valor es mayor que el segundo valor.

CompareDate resultados en:

• LessThanValue si ADate ocurre antes en el día especificado por BDate.


EqualsValue si las partes de tiempo de ADate y BDate son iguales,
ignorando la parte Fecha.
GreaterThanValue si ADate ocurre más tarde en el día especificado por
BDate.
• Ejemplo:

• var ThisMoment, AnotherMoment: TDateTime; ThisMoment: = Now; OtroMomento:


= IncHour (ThisMoment, 6); // agrega 6 horas // CompareDate (ThisMoment,
AnotherMoment) devuelve LessThanValue (-1) // CompareDate (AnotherMoment,
ThisMoment) devuelve GreaterThanValue (1

• Función de fecha
• Devuelve la fecha del sistema actual.

• Declaración:
tipo TDateTime = tipo Doble;

• fecha de la función : TDateTime;

• Descripción:
Devuelve la fecha del sistema actual.

• La parte integral de un valor TDateTime es la cantidad de días que han


transcurrido desde el 30/12/1899. La parte fraccional de un valor
TDateTime es la fracción de un día de 24 horas que ha transcurrido.

• Para encontrar el número fraccionario de días entre dos fechas,


simplemente reste los dos valores. Del mismo modo, para incrementar un
valor de fecha y hora en un cierto número fraccionario de días, simplemente
agregue el número fraccionario al valor de fecha y hora.

• Ejemplo: ShowMessage ('Today is' + DateToStr (Date));

• Función DateTimeToStr
• Convierte un valor TDateTime en una cadena (fecha y hora).

• Declaración:
tipo TDateTime = tipo Doble;

• función DayOfWeek (Fecha: TDateTime): entero;

• Descripción:
Devuelve el día de la semana para una fecha determinada.

• DayOfWeek devuelve un número entero entre 1 y 7, donde el domingo es el


primer día de la semana y el sábado es el séptimo.
DayOfTheWeek no cumple con la norma ISO 8601.

• Ejemplo:
• const Days: array [1..7] de string = ('Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday') ShowMessage ('Today is' + Days [DayOfWeek
(Date)]); //Hoy es Lunes

• Función DaysBetween
• Da la cantidad de días enteros entre dos fechas especificadas.

• Declaración:
función DaysBetween (const ANow, AThen: TDateTime): Integer;

• Descripción:
Da la cantidad de días enteros entre dos fechas especificadas.

• La función cuenta solo días completos. Lo que esto significa es que


devolverá 0 como resultado de la diferencia entre 05/01/2003 23:59:59 y
05/01/2003 23:59:58 - donde la diferencia real es de un * día completo
menos 1 segundo .

• Ejemplo:

• var dtNow, dtBirth: TDateTime; DaysFromBirth: entero; dtNow: = Ahora; dtBirth: =


EncodeDate (1973, 1, 29); DaysFromBirth: = DaysBetween (dtNow, dtBirth);
ShowMessage ('Zarko Gajic' existe "'+ IntToStr (DaysFromBirth) +' días completos!
');

• Función DateOf
• Devuelve solo la parte Fecha del valor TDateTime, configurando la parte
Tiempo en 0.

• Declaración:
función DateOf (Fecha: TDateTime): TDateTime

• Descripción:
Devuelve solo la parte Fecha del valor TDateTime, configurando la parte
Tiempo en 0.

• DateOf establece la porción de tiempo en 0, lo que significa medianoche.

• Ejemplo:

• var ThisMoment, ThisDay: TDateTime; ThisMoment: = Now; // -> 27/06/2003 10:


29: 16: 138 ThisDay: = DateOf (ThisMoment); // Este día: = 06/27/2003 00: 00: 00:
000

• Función DecodeDate
• Separa los valores de Año, Mes y Día desde un valor de TDateTime.
• Declaración:
procedimiento DecodeDate (Fecha: TDateTime; var Año, Mes, Día:
Palabra) ;;

• Descripción:
Separa los valores de Año, Mes y Día desde un valor de TDateTime.

• Si el valor dado de TDateTime es menor o igual a cero, los parámetros de


retorno de año, mes y día se establecen en cero.

• Ejemplo:

var Y, M, D: Word; DecodeDate (Fecha, Y, M, D); si Y = 2000 entonces ShowMessage ('¡Estás en un siglo "equivocado

• Función EncodeDate
Crea un valor de TDateTime a partir de los valores de Año, Mes y Día.

• Declaración:
función EncodeDate (año, mes, día: palabra): TDateTime

• Descripción:
Crea un valor de TDateTime a partir de los valores de Año, Mes y Día.

• El año debe estar entre 1 y 9999. Los valores de mes válidos son de 1 a 12.
Los valores de día válidos son de 1 a 28, 29, 30 o 31, según el valor del
mes.
Si la función falla, EncodeDate genera una excepción EConvertError.

• Ejemplo:

• var Y, M, D: Word; dt: TDateTime; y: = 2001; M: = 2; D: = 18; dt: = EncodeDate (Y,


M, D); ShowMessage ('Borna tendrá un año de antigüedad' + DateToStr (dt))

• Función FormatDateTime
Formatea un valor TDateTime para una cadena.

• Declaración:
función FormatDateTime ( const Fmt: cadena; Valor:
TDateTime): cadena ;

• Descripción:
Formatea un valor TDateTime para una cadena.

• FormatDateTime utiliza el formato especificado por el parámetro Fmt. Para


conocer los especificadores de formato compatibles, vaya a ver los archivos
de Ayuda de Delphi.
• Ejemplo:

• var s: cadena; d: TDateTime; ... d: = Ahora; // hoy + hora actual s: =


FormatDateTime ('dddd', d); // s: = Wednesday s: = FormatDateTime ('"Hoy es"
dddd "minute" nn', d) // s: = Hoy es miércoles, minuto 24

• Función IncDay
• Agrega o sustrae un número determinado de días desde un valor de fecha.

• Declaración:
función IncDay (ADate: TDateTime; Days: Integer = 1): TDateTime;

• Descripción:
Agrega o sustrae un número determinado de días desde un valor de fecha.

• Si el parámetro Días es negativo, la fecha devuelta es<="" p="">

• Ejemplo:

• var Fecha: TDateTime; EncodeDate (Fecha, 2003, 1, 29) // 29 de enero de 2003


IncDay (Fecha, -1) // 28 de enero de 2003

• Ahora funciona
• Devuelve la fecha y hora actual del sistema.

• Declaración:
tipo TDateTime = tipo Doble;

• función ahora: TDateTime;

• Descripción:
Devuelve la fecha y hora actual del sistema.

• La parte integral de un valor TDateTime es la cantidad de días que han


transcurrido desde el 30/12/1899. La parte fraccional de un valor
TDateTime es la fracción de un día de 24 horas que ha transcurrido.

• Para encontrar el número fraccionario de días entre dos fechas,


simplemente reste los dos valores. Del mismo modo, para incrementar un
valor de fecha y hora en un cierto número fraccionario de días, simplemente
agregue el número fraccionario al valor de fecha y hora.

• Ejemplo: ShowMessage ('Ahora es' + DateTimeToStr (Ahora));

• Años entre la función


• Da la cantidad de años enteros entre dos fechas especificadas.
• Declaración:
función YearsBetween ( const SomeDate, AnotherDate: TDateTime):
Integer;

• Descripción:
Da la cantidad de años enteros entre dos fechas especificadas.

• YearsBetween devuelve una aproximación basada en una suposición de


365.25 días por año.

• Ejemplo:

• var dtSome, dtAnother: TDateTime; DaysFromBirth: entero; dtSome: = EncodeDate


(2003, 1, 1); dtAnother: = EncodeDate (2003, 12, 31); YearsBetween (dtSome,
dtAnother) == 1 // año no bisiesto dtSome: = EncodeDate (2000, 1, 1); dtAnother:
= EncodeDate (2000, 12, 31); YearsBetween (dtSome, dtAnother) == 0 // año
bisiesto

Consultas con ADO - DB / 7


• by Zarko Gajic

SQL con TADOQuery

El componente TADOQuery proporciona a los desarrolladores de Delphi la


capacidad de obtener datos de una o varias tablas de una base de datos
ADO mediante SQL.

Estas sentencias SQL pueden ser sentencias DDL (lenguaje de definición de


datos) como CREATE TABLE, ALTER INDEX, etc., o pueden ser sentencias DML
(lenguaje de manipulación de datos), como SELECT, UPDATE y DELETE. La
declaración más común, sin embargo, es la instrucción SELECT, que produce una
vista similar a la disponible utilizando un componente Table.

Nota: aunque es posible ejecutar comandos usando el componente ADOQuery, el


componente ADOCommand es más apropiado para este propósito. Se usa con
más frecuencia para ejecutar comandos DDL o para ejecutar un procedimiento
almacenado (aunque debe usar TADOStoredProc para tales tareas) que no
devuelve un conjunto de resultados.

El SQL utilizado en un componente ADOQuery debe ser aceptable para el


controlador ADO en uso. En otras palabras, debe estar familiarizado con las
diferencias de escritura de SQL entre, por ejemplo, MS Access y MS SQL.
Al trabajar con el componente ADOTable, se accede a los datos en una base de
datos utilizando una conexión de almacén de datos establecida por el componente
ADOQuery utilizando su propiedad ConnectionString o mediante un componente
ADOConnection separado especificado en la propiedad Connection .

Para crear un formulario Delphi capaz de recuperar los datos de una base de
datos de Access con el componente ADOQuery, simplemente suelte todos los
componentes de acceso a los datos y datos relacionados y haga un enlace como
se describe en los capítulos anteriores de este curso.

Los componentes de acceso a datos: DataSource, ADOConnection junto con


ADOQuery (en lugar de ADOTable) y un componente de datos como DBGrid es
todo lo que necesitamos.
Como ya se explicó, al usar el Inspector de objetos, establezca el vínculo entre
esos componentes de la siguiente manera:

DBGrid1.DataSource = DataSource1
DataSource1.DataSet = ADOQuery1
ADOQuery1.Connection = ADOConnection1
// construimos ConnectionString
ADOConnection1.ConnectionString = ...

ADOConnection1.LoginPrompt = False

Hacer una consulta SQL

El componente TADOQuery no tiene una propiedad TableName como lo hace


TADOTable. TADOQuery tiene una propiedad (TStrings) llamada SQL que se usa
para almacenar la declaración SQL. Puede establecer el valor de la propiedad
SQL con el Inspector de Objetos en tiempo de diseño o mediante código en
tiempo de ejecución.

En el momento del diseño, invoque el editor de propiedades para la propiedad


SQL haciendo clic en el botón de puntos suspensivos en el Inspector de Objetos.
Escriba la siguiente instrucción SQL: "SELECT * FROM Authors".

La instrucción SQL se puede ejecutar de una de dos maneras, dependiendo del


tipo de declaración. Los enunciados del lenguaje de definición de datos
generalmente se ejecutan con el método ExecSQL . Por ejemplo, para eliminar un
registro específico de una tabla específica, puede escribir una declaración
DELETE DDL y ejecutar la consulta con el método ExecSQL.
Las sentencias SQL (ordinarias) se ejecutan estableciendo la
propiedad TADOQuery.Active en True o llamando al método Open (esencialmente
igual). Este enfoque es similar a recuperar datos de una tabla con el componente
TADOTable.
En tiempo de ejecución, la instrucción SQL en la propiedad SQL se puede usar
como cualquier objeto StringList:

con ADOQuery1 do begin Close; SQL.Clear; SQL.Add: = 'SELECT * FROM Authors' SQL.Add: = 'ORDER BY authornam

El código anterior, en tiempo de ejecución, cierra el conjunto de datos, vacía la


cadena SQL en la propiedad SQL, asigna un nuevo comando SQL y activa el
conjunto de datos llamando al método Open.

Tenga en cuenta que obviamente crear una lista persistente de objetos de campo
para un componente ADOQuery no tiene sentido. La próxima vez que llame al
método Open, el SQL puede ser tan diferente que el conjunto completo de
nombres archivados (y tipos) puede cambiar. Por supuesto, este no es el caso si
estamos usando ADOQuery para obtener las filas de una sola tabla con el
conjunto constante de campos, y el conjunto resultante depende de la parte
WHERE de la declaración SQL.

Consultas dinámicas

Una de las grandes propiedades de los componentes TADOQuery es la propiedad


Params. Una consulta parametrizada es aquella que permite la selección flexible
de fila / columna utilizando un parámetro en la cláusula WHERE de una instrucción
SQL.

La propiedad Params permite parámetros reemplazables en la declaración SQL


predefinida. Un parámetro es un marcador de posición para un valor en la cláusula
WHERE, definida justo antes de que se abra la consulta. Para especificar un
parámetro en una consulta, use dos puntos (:) que preceden a un nombre de
parámetro.

En el momento del diseño, use el Inspector de Objetos para establecer la


propiedad SQL de la siguiente manera:

ADOQuery1.SQL: = 'SELECCIONAR * FROM Aplicaciones WHERE type = :


apptype '

Cuando cierre la ventana del editor de SQL, abra la ventana Parámetros haciendo
clic en el botón de puntos suspensivos en el Inspector de Objetos.

El parámetro en la declaración SQL precedente se llama apptype . Podemos


establecer los valores de los parámetros en la colección de parámetros en tiempo
de diseño a través del cuadro de diálogo Parámetros, pero la mayoría de las veces
cambiaremos los parámetros en el tiempo de ejecución. El cuadro de diálogo
Parámetros se puede usar para especificar los tipos de datos y los valores
predeterminados de los parámetros utilizados en una consulta.
En tiempo de ejecución, los parámetros se pueden cambiar y la consulta se puede
volver a ejecutar para actualizar los datos. Para ejecutar una consulta
parametrizada, es necesario proporcionar un valor para cada parámetro antes de
la ejecución de la consulta. Para modificar el valor del parámetro, usamos la
propiedad Params o el método ParamByName. Por ejemplo, dada la instrucción
SQL anterior, en tiempo de ejecución podríamos usar el siguiente código:

con ADOQuery1 do begin Close; SQL.Clear; SQL.Add ('SELECT * FROM Aplicaciones WHERE type = : apptype '); Para
('apptype'). Value: = 'multimedia'; Abierto; fin ;

Navegando y editando la consulta

Al igual que al trabajar con el componente ADOTable, ADOQuery devuelve un


conjunto o registros de una tabla (o dos o más).

La navegación a través de un conjunto de datos se realiza con el mismo conjunto


de métodos que se describe en el capítulo "Detrás de los datos en los conjuntos
de datos".

En general, el componente ADOQuery no se debe usar cuando se realiza la


edición. Las consultas basadas en SQL se utilizan principalmente para informes.
Si su consulta arroja un conjunto de resultados, a veces es posible editar el
conjunto de datos devuelto. El conjunto de resultados debe contener registros de
una sola tabla y no debe usar ninguna función agregada de SQL. La edición de un
conjunto de datos devuelto por ADOQuery es lo mismo que editar el conjunto de
datos de ADOTAble.

Un ejemplo

Para ver alguna acción ADOQuery, codificaremos un pequeño ejemplo. Hagamos


una consulta que pueda usarse para obtener las filas de varias tablas en una base
de datos. Para mostrar la lista de todas las tablas en una base de datos, podemos
usar el método GetTableNames del componente ADOConnection .
GetTableNames en el evento OnCreate del formulario llena el ComboBox con los
nombres de la tabla y el botón se utiliza para cerrar la consulta y recrearla para
recuperar los registros de una tabla elegida. Los controladores de eventos ()
deben verse así:

procedure TForm1.FormCreate (Sender: TObject); comience ADOConnection1.GetTableNames


(ComboBox1.Items); fin ; procedure TForm1.Button1Click (Sender: TObject); var tblname: cadena ; comenzar si Com
luego sale; tblname: = ComboBox1.Items [ComboBox1.ItemIndex]; con ADOQuery1 do begin Close; SQL.Text: = 'SEL
tblname; Abierto; fin ; fin ;

Tenga en cuenta que todo esto se puede hacer mediante el uso de ADOTable y su
propiedad TableName.

Cómo hacer una lista desplegable en un


DBGrid
• by Zarko Gajic

¿Desea crear la mejor cuadrícula de edición de datos? A continuación se incluyen


instrucciones para crear una interfaz de usuario para editar campos de
búsqueda dentro de un DBGrid . Específicamente, veremos cómo colocar un
DBLookupComboBox en una celda de un DBGrid.

Lo que esto hará es recurrir a la información de una fuente de datos que se


utilizará para rellenar un cuadro desplegable.

Para mostrar un DBLookupComboBox dentro de una celda de un DBGrid , primero


necesita hacer uno disponible en tiempo de ejecución ...

Crear una búsqueda con un DBLookupComboBox


Seleccione la página "Controles de datos" en la Paleta de componentes y elija un
DBLookupComboBox. Coloque uno en cualquier lugar del formulario y deje el
nombre predeterminado de "DBLookupComboBox1". No importa dónde lo
coloque, ya que la mayoría de las veces, será invisible o flotante en la red.

Agregue un componente DataSource y DataSet más para "completar" el cuadro


combinado con valores. Coloque un TDataSource (con el nombre DataSource2) y
TAdoQuery (asígnele el nombre AdoQuery1) en cualquier lugar del formulario.

Para que DBLookupComboBox funcione correctamente, se deben establecer


varias propiedades más; son la clave de la conexión de búsqueda:

▪ DataSource y DataField determinan la conexión principal. DataField es un campo en el


que insertamos los valores buscados.
▪ ListSource es la fuente del conjunto de datos de búsqueda.
▪ KeyField identifica el campo en el ListSource que debe coincidir con el valor del
campo DataField .
▪ ListFields es el campo (s) del conjunto de datos de búsqueda que se muestran
realmente en el combo. ListField puede mostrar más de un campo, pero los múltiplos
deben estar separados por punto y coma.

Debe establecer un valor suficientemente grande para DropDownWidth (de un


ComboBox) para ver realmente varias columnas de datos.

A continuación, se explica cómo configurar todas las propiedades importantes del


código (en el controlador de eventos OnCreate del formulario):
procedure TForm1.FormCreate (Sender:
TObject); comience con DBLookupComboBox1 do begin DataSource: = DataSource1; // -
> AdoTable1 -> DBGrid1 ListSource: = DataSource2; DataField: = 'AuthorEmail'; // desde
AdoTable1 - que se muestra en DBGrid KeyField: = 'Correo electrónico'; ListFields: =
'Nombre; Email'; Visible: = Falso; fin ; DataSource2.DataSet: = AdoQuery1;
AdoQuery1.Connection: = AdoConnection1; AdoQuery1.SQL.Text: = 'SELECT Name, Email
FROM Authors'; AdoQuery1.Open; fin ;
Nota: Cuando desee mostrar más de un campo en un DBLookupComboBox,
como en el ejemplo anterior, debe asegurarse de que todas las columnas estén
visibles. Esto se hace estableciendo la propiedad DropDownWidth.

Sin embargo, verá que inicialmente, tiene que establecer esto en un valor muy
grande que da como resultado que la lista eliminada sea demasiado amplia (en la
mayoría de los casos). Una solución consiste en establecer el ancho de
visualización de un campo en particular que se muestra en una lista desplegable.

Este código, ubicado dentro del evento OnCreate para el formulario, garantiza que
tanto el nombre del autor como su correo electrónico se muestren dentro de la lista
desplegable:

AdoQuery1.FieldByName ('Correo electrónico'). DisplayWidth: = 10;


AdoQuery1.FieldByName ('Name'). DisplayWidth: = 10; AdoQuery1.DropDownWidth: =
150;

Lo que nos queda por hacer, es hacer que un cuadro combinado pase el mouse
sobre una celda (cuando está en modo de edición), mostrando el campo
AuthorEmail. En primer lugar, debemos asegurarnos de que
DBLookupComboBox1 se mueva y clasifique sobre la celda en la que se muestra
el campo AuthorEmail.

procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect; DataCol:


Entero; Columna: TColumn; Estado: TGridDrawState); begin if (gdFocused en State)
y luego comience if (Column.Field.FieldName = DBLookupComboBox1.DataField)
y luego con DBLookupComboBox1 empiece Left: = Rect.Left + DBGrid1.Left + 2; Superior:
= Rect.Top + DBGrid1.Top + 2; Ancho: = Rect.Right - Rect.Left; Ancho: = Rect.Right -
Rect.Left; Altura: = Rect.Bottom - Rect.Top; Visible: = Verdadero; fin ; extremo final ;

A continuación, cuando salgamos de la celda, tenemos que ocultar el cuadro


combinado:

procedure TForm1.DBGrid1ColExit (Sender:


TObject); comience si DBGrid1.SelectedField.FieldName = DBLookupComboBox1.DataField
y luego DBLookupComboBox1.Visible: = False end ;

Tenga en cuenta que cuando está en el modo de edición, todas las pulsaciones de
teclado van a la celda de DBGrid, pero debemos asegurarnos de que se envíen a
DBLookupComboBox. En el caso de un DBLookupComboBox, estamos
interesados principalmente en la tecla [Tab]; debería mover el foco de entrada a la
siguiente celda.

procedure TForm1.DBGrid1KeyPress (Sender: TObject; var Key: Char); comience si (clave =


Chr (9)) luego Salga; if (DBGrid1.SelectedField.FieldName =
DBLookupComboBox1.DataField) entonces comienza DBLookupComboBox1.SetFocus;
SendMessage (DBLookupComboBox1.Handle, WM_Char, palabra (clave),
0); extremo final ;

Cuando selecciona un elemento ("fila") desde un DBLookupComboBox, el valor o


el campo KeyField correspondiente se almacena como el valor del
campo DataField .

Sincronización de subprocesos y GUI en


una aplicación Delphi
• by Zarko Gajic
• Código de ejemplo para una aplicación GUI Delphi con varios subprocesos

• Multi-threading en Delphi le permite crear aplicaciones que incluyen varias


rutas de ejecución simultáneas.

• Una aplicación Delphi "normal" tiene un único subproceso, lo que significa


que todos los objetos (VCL) acceden a sus propiedades y ejecutan sus
métodos dentro de este único subproceso. Para acelerar el procesamiento
de datos en su aplicación, puede decidir incluir uno o más subprocesos
"secundarios".

• Hilos y GUI
• Cuando se ejecutan varios subprocesos en la aplicación, surge la pregunta
de cómo puede actualizar su interfaz gráfica de usuario (GUI) como
resultado de la ejecución de un subproceso.
• La respuesta está en el método Sincronizar de la clase TThread.

• Para actualizar la interfaz de usuario o el hilo principal de la aplicación


desde una secuencia secundaria, debe llamar al método Sincronizar. Este
es un método seguro para subprocesos que evita conflictos de subprocesos
múltiples que pueden surgir al acceder a propiedades de objetos o métodos
que no son seguros para subprocesos o que utilizan recursos que no están
en el hilo principal de ejecución.

• A continuación se muestra una demostración de ejemplo que utiliza varios


botones con barras de progreso, cada barra de progreso muestra el
"estado" actual de la ejecución de la secuencia.

• > unidad MainU; la interfaz usa Windows, Mensajes, SysUtils, Variantes, Clases,
Gráficos, Controles, Formularios, Diálogos, ComCtrls, StdCtrls, ExtCtrls; tipo // clase
de interceptor TButton = clase (StdCtrls.TButton) OwnedThread:
TThread; ProgressBar: TProgressBar; fin ; TMyThread
= clase (TThread) private FCounter: Integer; FCountTo: Integer; FProgressBar:
TProgressBar; FOwnerButton:
TButton; procedimiento DoProgress; procedimiento SetCountTo (const Value:
Integer); procedimiento SetProgressBar (valor de const:
TProgressBar); procedimiento SetOwnerButton (valor de const:
TButton); procedimiento protegido Ejecutar; anular ; public constructor Create
(CreateSuspended: Boolean); propiedad CountTo:
Integer read FCountTo write SetCountTo; propiedad ProgressBar:
TProgressBar leer FProgressBar escribir SetProgressBar; property OwnerButton:
TButton read FOwnerButton escribe SetOwnerButton; fin; TMainForm
= class (TForm) Button1: TButton; ProgressBar1: TProgressBar; Button2:
TButton; ProgressBar2: TProgressBar; Button3: TButton; ProgressBar3:
TProgressBar; Button4: TButton; ProgressBar4: TProgressBar; Button5:
TButton; ProgressBar5: TProgressBar; procedimiento Button1Click (Sender:
TObject); fin ; var MainForm: TMainForm; implementación {$ R *
.dfm} {TMyThread} constructor TMyThread.Create (CreateSuspended:
Boolean); comenzar heredado; FCounter: = 0; FCountTo: =
MAXINT; fin ; procedimiento TMyThread.DoProgress; var PctDone:
Extended; begin PctDone: = (FCounter / FCountTo); FProgressBar.Position: = Round
(FProgressBar.Step * PctDone); FOwnerButton.Caption: = FormatFloat ('0.00%',
PctDone * 100); fin ; procedimiento TMyThread.Execute; const Interval =
1000000; comenzar FreeOnTerminate: = Verdadero; FProgressBar.Max: =
FCountTo div Interval; FProgressBar.Step: =
FProgressBar.Max; mientras FCounter do comienza si FCounter mod Interval =
0 entonces Synchronize (DoProgress); Inc (FCounter); fin ; FOwnerButton.Caption:
= 'Inicio'; FOwnerButton.OwnedThread: = nil ; FProgressBar.Position: =
FProgressBar.Max; fin ; procedimiento TMyThread.SetCountTo (valor de const :
entero); begin FCountTo: = Value; fin ; procedimiento TMyThread.SetOwnerButton
(valor de const : TButton); begin FOwnerButton: =
Valor; fin ; procedimiento TMyThread.SetProgressBar (valor de const :
TProgressBar); comenzar FProgressBar: =
Value; fin ; procedimiento TMainForm.Button1Click (Sender: TObject); var aButton:
TButton; aThread: TMyThread; aProgressBar: TProgressBar; begin aButton: = TButton
(emisor); si no está asignado (aButton.OwnedThread), entonces comienza aThread:
= TMyThread.Create (True); aButton.OwnedThread: = aThread; aProgressBar: =
TProgressBar (FindComponent (StringReplace (aButton.Name, 'Button', 'ProgressBar',
[]))); aThread.ProgressBar: = aProgressBar; aThread.OwnerButton: =
aButton; aThread.Resume; aButton.Caption: = 'Pausa'; end else
begin si aButton.OwnedThread.Suspended then aButton.OwnedThread.Resume else
aButton.OwnedThread.Suspend; aButton.Caption: = 'Ejecutar'; fin ; fin ; fin

• Nota: El código utilizado aquí fue enviado por Jens Borrisholt.

Cómo ocultar las pestañas del control


Delphi de TPageControl
• by Zarko Gajic

Crear una interfaz de usuario similar a un asistente

El control TPageControl Delphi muestra un conjunto de páginas utilizadas para


crear un cuadro de diálogo de varias páginas. Cada página, una hoja de pestañas,
aloja sus propios controles. El usuario selecciona una página (la hace visible)
haciendo clic en la pestaña de la página que aparece en la parte superior del
control.

Ocultar las pestañas de PageControl

Si necesita crear una interfaz de usuario similar a un asistente donde tenga los
botones "Siguiente" y "Anterior" "moviendo" un usuario hacia adelante y hacia
atrás a través de un conjunto de páginas (cuadros de diálogo), es posible que
desee ocultar las pestañas de PageControl y por lo tanto, no se permite
seleccionar una página en particular por medio del mouse del usuario.

El truco está en establecer la propiedad TabVisible en falso para cada una de las
hojas (objeto TTabSheet) del control de página.
Activar la página utilizando las propiedades
ActivePage o ActivePageIndex PageControl no generará
los eventos OnChange y OnChanging .

Para establecer programáticamente la página activa, use el


método SelectNextPage .

> // Ocultar las pestañas de PageControl var page: integer; begin for page: =
0 a PageControl1.PageCount - 1 comenzar con PageControl1.Pages [página]
.TabVisible: = false; fin ; // seleccione la primera
pestaña PageControl1.ActivePageIndex: = 0; (* O configure la página activa
directamente PageControl1.ActivePage: = TabSheet1; Nota: las dos anteriores NO
generan los eventos OnChanging y OnChange
*) end ; procedure TForm1.PageControl1Changing (Sender:
TObject; var AllowChange: Boolean); begin // no change if en la última
página AllowChange: = PageControl1.ActivePageIndex <-1 +
PageControl1.PageCount; fin ; // Seleccione el procedimiento de la pestaña
"Anterior" TForm1.PreviousPageButtonClick (Sender:
TObject); comience PageControl1.SelectNextPage (falso, falso); fin ; // Seleccione
el procedimiento de la pestaña "Siguiente" TForm1.NextPageButtonClick (Sender:
TObject); comience PageControl1.SelectNextPage (verdadero, falso); fin ;
El uso de esta técnica desordene el formulario, lo que lleva a una interfaz más
optimizada, pero asegúrese de que la disposición de los controles en cada
pestaña no obligue al usuario a moverse con frecuencia entre pestañas.

Directivas de la versión Delphi Compiler


• by Zarko Gajic

Preparándose para codificar sin barreras. Vea cómo superar el problema de la


versión del compilador: compilar el código Delphi para varias versiones de Delphi.

Si planea escribir el código Delphi que debería funcionar con varias versiones del
compilador Delphi, necesita saber en qué versiones se compila su código.

Supongamos que está escribiendo su propio componente


personalizado (comercial). Los usuarios de su componente pueden tener
diferentes versiones de Delphi que usted.

Si intentan recompilar el código del componente (tu código), ¡podrían tener


problemas! ¿Qué sucede si usa parámetros predeterminados en sus funciones y
el usuario tiene Delphi 3?

Directiva del compilador: $ IfDef


Las directivas de compilación son comentarios de sintaxis especiales que
podemos usar para controlar las características del compilador Delphi. El
compilador Delphi tiene tres tipos de directivas: directivas de
conmutación , directivas de parámetros y directivas condicionales . La
compilación condicional nos permite compilar selectivamente partes de un código
fuente dependiendo de las condiciones establecidas.

La directiva del compilador $ IfDef inicia una sección de compilación condicional.

La sintaxis se ve así:

> {$ IfDef DefName} ... {$ Else} ... {$ EndIf}


DefName presenta el llamado símbolo condicional. Delphi define varios símbolos
condicionales estándar. En el "código" anterior, si se define DefName, se
compilará el código por encima de $ Else .

Símbolos de la versión Delphi

Un uso común para la directiva $ IfDef es probar la versión del compilador Delphi.

La siguiente lista indica los símbolos para verificar al compilar condicionalmente


para una versión particular del compilador Delphi:

▪ SÍMBOLO - VERSIÓN COMPILADOR


▪ VER80 - Delphi 1
▪ VER90 - Delphi 2
▪ VER100 - Delphi 3
▪ VER120 - Delphi 4
▪ VER130 - Delphi 5
▪ VER140 - Delphi 6
▪ VER150 - Delphi 7
▪ VER160 - Delphi 8
▪ VER170 - Delphi 2005

▪ VER180 - Delphi 2006


▪ VER180 - Delphi 2007
▪ VER185 - Delphi 2007
▪ VER200 - Delphi 2009
▪ VER210 - Delphi 2010
▪ VER220 - Delphi XE
▪ VER230 - Delphi XE2
▪ WIN32 : indica que el entorno operativo es la API de Win32.
▪ LINUX : indica que el entorno operativo es Linux
▪ MSWINDOWS : indica que el entorno operativo es MS Windows / li]
▪ CONSOLA - Indica que una aplicación se está compilando como una aplicación
de consola
Al conocer los símbolos anteriores, es posible escribir código que funcione con
varias versiones de Delphi mediante el uso de directivas de compilación para
compilar el código fuente apropiado para cada versión.

Nota: el símbolo VER185, por ejemplo, se usa para indicar el compilador de Delphi
2007 o una versión anterior.

Usar símbolos "VER"

Es bastante habitual (y deseable) que cada nueva versión de Delphi agregue


varias rutinas nuevas de RTL al lenguaje.

Por ejemplo, la función IncludeTrailingBackslash, introducida en Delphi 5, agrega


"\" al final de una cadena si aún no está allí. En el proyecto Delphi MP3, he usado
esta función y varios lectores se han quejado de que no pueden compilar el
proyecto; tienen alguna versión Delphi anterior a Delphi 5.

Una forma de resolver este problema es crear su propia versión de esta rutina: la
función AddLastBackSlash.

Si el proyecto debe compilarse en Delphi 5, se llama a IncludeTrailingBackslash.


Si se utilizan algunas de las versiones anteriores de Delphi, simulamos la función
IncludeTrailingBackslash.

Podría verse algo así como:

> función AddLastBackSlash (str: cadena ): cadena ; begin {$ IFDEF


VER130} Resultado: = IncludeTrailingBackslash (str); {$ ELSE} si Copy (str, Length
(str), 1) = "\" then > Result: = str else Resultado: = str + "\";> {$ ENDIF} end ;
Cuando llama a la función AddLastBackSlash, Delphi averigua qué parte de la
función debe usarse y la otra parte simplemente se salta.

Delphi 2008?
Delphi 2007 usa VER180 para mantener la compatibilidad sin interrupciones con
Delphi 2006 y luego agrega VER185 para el desarrollo que específicamente
necesita apuntar a Delphi 2007 por cualquier razón.

Nota: cada vez que la interfaz de una unidad cambia, el código que usa esa
unidad debe volver a compilarse.
Delphi 2007 es un lanzamiento sin interrupciones, lo que significa que los
archivos DCU de Delphi 2006 funcionarán tal como están.

Establecer CheckBox. Comprobado sin el


evento OnClick
• by Zarko Gajic
• Mostrar la Propiedad Protegida Deshabilitada por Clicks

• El control TCheckBox Delphi muestra una casilla de verificación que puede


estar activada (marcada) o desactivada (desactivada). La propiedad
Comprobada especifica si la casilla de verificación está marcada o no.

• Cuando el usuario hace clic en la casilla de verificación para cambiar su


estado Comprobado, se activa el evento OnClick para la casilla de
verificación.

• Cambiar la propiedad comprobada de Checkbox


• Como no hay ningún evento OnCheckedChanged , probablemente maneje
la lógica del programa en función del estado marcado de la casilla de
verificación en su evento OnClick.

• Sin embargo, si modifica la propiedad Comprobada mediante


programación, se activará el evento OnClick, aunque no se haya
producido ninguna interacción entre los usuarios.

• Hay (al menos) dos formas de cambiar mediante programación la propiedad


marcada de la casilla de verificación mientras "deshabilita" el evento
OnClick.

• Quite el controlador OnClick, cambie marcado, vuelva al controlador


original OnClick
• En Delphi para Win32, un evento puede tener solo un controlador de
eventos (procedimiento) asociado (aunque hay una forma de imitar eventos
de multidifusión en Delphi para Win32). La firma del evento OnClick de un
control TCheckBox es "tipo TNotifyEvent = procedure (Sender: TObject) of
object;"
• Si asigna NIL al evento OnClick antes de cambiar el estado de la casilla de
verificación, vuelva al procedimiento original de manejo de eventos OnClick:
el evento OnClick no se disparará.

• > procedimiento SetCheckedState ( const checkBox: TCheckBox; const check:


boolean); var onClickHandler:
TNotifyEvent; comience con checkbox; comience onClickHandler: =
OnClick; OnClick: = nil ; Controlado: = verificar; OnClick: = onClickHandler; fin ; fin ;

• El uso de este procedimiento es simple:

• > // alternar Estado comprobado begin SetCheckedState (CheckBox1, NOT


CheckBox1.Checked); fin ;

• SetCheckedState anterior activa la casilla de verificación Checked property


of CheckBox1.

• Hack protegido: ClicksDisabled: = true


• Otra forma de detener la ejecución de OnClick, cuando se cambia la
propiedad Comprobada de una casilla de verificación, es aprovechar la
propiedad ClicksDisabled "oculta" (protegida).

• Al observar el procedimiento SetState de TCheckBox que se ejecuta cada


vez que cambia la propiedad Comprobada, OnCick se activa si
ClicksDisable no es verdadero.

• Como ClicksDisabled está protegido, no puede acceder a él desde


su código .

• Afortunadamente, la técnica de hack protegido le permite acceder a esas


propiedades ocultas / protegidas de un control Delphi.

• Los miembros protegidos de acceso de un componente proporcionan más


información sobre el tema.

• Lo que debe hacer es declarar una clase ficticia simple que amplíe
TCheckBox en la misma unidad donde utilizará la propiedad
ClickSDisabled.

• Una vez que tenga en sus manos ClicksDisabled, simplemente configúrelo


en verdadero, cambie la propiedad Comprobada, luego configure
ClicksDisabled en falso (valor predeterminado):

• > escriba TCheckBoxEx = clase (TCheckBox); ... con TCheckBoxEx


(CheckBox1) comienzan ClickSDisabled: = true; Marcado: = NO
verificado; ClicksDisabled: = falso; fin ;
• Nota: el código anterior activa la propiedad Comprobada de la casilla de
verificación denominada "CheckBox1" utilizando la propiedad
ClicksDisabled protegida.

Consultas de base de datos Delphi


multiproceso
• by Zarko Gajic

Cómo ejecutar consultas de bases de datos utilizando varios hilos

Por diseño, una aplicación Delphi se ejecuta en un hilo. Para acelerar algunas
partes de la aplicación, quizás desee agregar varias rutas de ejecución
simultáneas en su aplicación Delphi .

Multithreading en aplicaciones de bases de datos

En la mayoría de los escenarios, las aplicaciones de bases de datos que usted


crea con Delphi tienen un único hilo: debe finalizar una consulta que ejecute contra
la base de datos (procesamiento de los resultados de la consulta) antes de poder
obtener otro conjunto de datos.

Para acelerar el procesamiento de datos, por ejemplo, obtener datos de la base de


datos para crear informes, puede agregar un hilo adicional para buscar y operar el
resultado (conjunto de registros).

Continúe leyendo para obtener información acerca de las 3 trampas en


las consultas de base de datos ADO multiproceso:

1. Resolver: " No se llamó CoInitialize ".


2. Resuelve: "El lienzo no permite dibujar ".
3. ¡TADoConnection principal no se puede usar!

Cliente - Pedidos - Artículos

En el caso bien conocido en el que un cliente coloca pedidos que contienen


artículos, es posible que deba mostrar todos los pedidos para un cliente en
particular a lo largo del número total de artículos por cada pedido.

En una aplicación de subproceso único "normal", necesitaría ejecutar la consulta


para buscar los datos y luego iterar sobre el conjunto de registros para mostrar los
datos.
Si desea ejecutar esta operación para más de un cliente, debe ejecutar
secuencialmente el procedimiento para cada uno de los clientes
seleccionados .

En un escenario multiproceso, puede ejecutar la consulta de la base de datos


para cada cliente seleccionado en un hilo separado y, por lo tanto, hacer que
el código se ejecute varias veces más rápido.

Multithreading en dbGO (ADO)

Supongamos que desea mostrar pedidos para 3 clientes seleccionados en un


control de cuadro de lista Delphi.

> escriba TCalcThread


= clase (TThread) procedimiento privado RefreshCount; procedimiento protegido
Ejecutar; anular ; ConnStr público : widestring; SQLString: widestring; ListBox:
TListBox; Prioridad: TThreadPriority; TicksLabel: TLabel; Ticks: Cardinal; fin ;
Esta es la parte de la interfaz de una clase de subprocesos personalizados que
vamos a utilizar para obtener y operar en todos los pedidos para un cliente
seleccionado.

Cada orden se muestra como un elemento en un control de cuadro de lista


(campo ListBox ). El campo ConnStr contiene la cadena de conexión
ADO. TicksLabel contiene una referencia a un control TLabel que se usará para
mostrar los tiempos de ejecución de subprocesos en un procedimiento
sincronizado.

El procedimiento RunThread crea y ejecuta una instancia de la clase de


subproceso TCalcThread.

> function TADOThreadedForm.RunThread (SQLString: widestring; LB: TListBox;


Prioridad: TThreadPriority; lbl: TLabel): TCalcThread; var CalcThread:
TCalcThread; begin CalcThread: = TCalcThread.Create
(true); CalcThread.FreeOnTerminate: = verdadero; CalcThread.ConnStr: =
ADOConnection1.ConnectionString; CalcThread.SQLString: =
SQLString; CalcThread.ListBox: = LB; CalcThread.Priority: =
Prioridad; CalcThread.TicksLabel: = lbl; CalcThread.OnTerminate: =
ThreadTerminated; CalcThread.Resume; Resultado: = CalcThread; fin ;
Cuando se seleccionan los 3 clientes del cuadro desplegable, creamos 3
instancias de CalcThread:

> var s, sg: widestring; c1, c2, c3: entero; begin s: = 'SELECT O.SaleDate, MAX
(I.ItemNo) AS ItemCount' + 'FROM Customer C, Orders O, Items I' + 'WHERE
C.CustNo = O.CustNo AND I.OderNo = O.OrderNo' ; sg: = 'GROUP BY
O.SaleDate'; c1: = Integer (ComboBox1.Items.Objects [ComboBox1.ItemIndex]); c2: =
Integer (ComboBox2.Items.Objects [ComboBox2.ItemIndex]); c3: = Entero
(ComboBox3.Items.Objects [ComboBox3.ItemIndex]); Leyenda: = ''; ct1: = RunThread
(Formato ('% s Y C.CustNo =% d% s', [s, c1, sg]), lbCustomer1, tpTimeCritical,
lblCustomer1); ct2: = RunThread (Formato ('% s Y C.CustNo =% d% s', [s, c2, sg]),
lbCliente2, tpNormal, lblCliente2); ct3: = RunThread (Formato ('% s Y C.CustNo =%
d% s', [s, c3, sg]), lbCustomer3, tpLowest, lblCustomer3); fin ;

Trampas y trucos - Consultas ADO multiproceso

El código principal va en el método Execute del subproceso:

> procedure TCalcThread.Execute; var Qry: TADOQuery; k:


entero; ser gin heredado ; CoInicializar (nil); // CoInitialize no se llamó Qry: =
TADOQuery.Create ( nil ); intente // DEBE UTILIZAR CONEXIÓN PROPIA //
Qry.Connection: = Form1.ADOConnection1; Qry.ConnectionString: =
ConnStr; Qry.CursorLocation: = clUseServer; Qry.LockType: =
ltReadOnly; Qry.CursorType: = ctOpenForwardOnly; Qry.SQL.Text: =
SQLString; Qry.Open; mientras que no Qry.Eof y NOT Terminated comiencen
ListBox.Items.Insert (0, Format ('% s -% d', [Qry.Fields [0] .asString, Qry.Fields [1]
.AsInteger])); // Canvas NO permite el dibujo si no se llama a través de
Sincronizar Sincronizar
(RefreshCount); Qry.Next; fin ; finalmente Qry.Free; fin; CoUninitialize (); fin ;
Hay tres trampas que necesita saber cómo resolver al crear aplicaciones de bases
de datos Delphi ADO multiproceso :

1. CoInitialize y CoUninitialize deben invocarse manualmente antes de utilizar


cualquiera de los objetos dbGo. Si no se llama a CoInitialize, se producirá la
excepción " CoInitialize was not called ". El método CoInitialize inicializa la
biblioteca COM en el hilo actual. ADO es COM.
2. Usted * no puede * usar el objeto TDOConnection desde el hilo principal
(aplicación). Cada hilo necesita crear su propia conexión de base de datos.
3. Debe utilizar el procedimiento Sincronizar para "hablar" con el hilo principal y
acceder a los controles en el formulario principal.

Propietario vs. Padre en aplicaciones


Delphi
• by Zarko Gajic
• ¡Cada vez que colocas un panel en un formulario y un botón en ese panel,
haces una conexión "invisible"! El formulario se convierte en
el propietario del botón y el panel está configurado para ser su principal .

• Cada componente de Delphi tiene una propiedad de Propietario. El


Propietario se encarga de liberar los componentes de propiedad cuando se
libera.

• Similar, pero diferente, la propiedad Parent indica el componente que


contiene el componente "secundario".

• Padre
• Parent se refiere al componente en el que está contenido otro componente,
como TForm, TGroupBox o TPanel. Si un control (principal) contiene otros,
los controles contenidos son controles secundarios del padre.

• El padre determina cómo se muestra el componente. Por ejemplo, las


propiedades Izquierda y Superior son todas relativas al Padre.

• La propiedad principal se puede asignar y cambiar durante el tiempo de


ejecución.

• No todos los componentes tienen el padre. Muchas formas no tienen un


padre. Por ejemplo, los formularios que aparecen directamente en el
escritorio de Windows tienen Parent establecido en nil. El
método HasParent de un componente devuelve un valor booleano que
indica si el componente ha recibido o no un padre.

• Usamos la propiedad Parent para obtener o establecer el elemento primario


de un control. Por ejemplo, coloque dos paneles (Panel1, Panel2) en un
formulario y coloque un botón (Botón1) en el primer panel (Panel1). Esto
establece la propiedad principal de Button en Panel1.

• > Button1.Parent: = Panel2;

• Si coloca el código anterior en el evento OnClick para el segundo Panel, al


hacer clic en Panel2, el botón "salta" del Panel1 al Panel2: Panel1 ya no es
el Padre para el Botón.

• Cuando desee crear un TButton en tiempo de ejecución, es importante


recordar asignar un elemento primario: el control que contiene el botón.

• Para que un componente sea visible, debe tener un padre para mostrarse
dentro de él .

• ParentThis y ParentThat
• Si selecciona un botón en el momento del diseño y mira el Inspector de
Objetos, notará varias propiedades "para padres". El ParentFont , por
ejemplo, indica si la Fuente utilizada para el título del Botón es la misma
que la utilizada para el elemento primario del Botón (en el ejemplo anterior:
Panel1). Si ParentFont es Verdadero para todos los Botones en un Panel,
al cambiar la propiedad de Fuente del panel a Negrita, todos los leyendas
del Botón en el Panel usarán esa fuente (negrita).

• Propiedad de controles
• Todos los componentes que comparten el mismo Parent están disponibles
como parte de la propiedad Controls de ese Parent. Por ejemplo, los
controles se pueden usar para iterar sobre todos los elementos secundarios
del control de ventana .

• La siguiente pieza de código se puede usar para ocultar todos los


componentes contenidos en Panel1:

• > para ii: = 0 para Panel1.ControlCount - 1 do Panel1.Controles [ii] .Visible: = falso;

• Trucos de engaño
• Los controles con ventana tienen tres características básicas: pueden
recibir el foco de entrada, usan recursos del sistema y pueden ser padres
de otros controles.

• Por ejemplo, el componente Button es un control de ventana y no puede ser


el elemento principal de otro componente; no puede colocar otro
componente en él.

• El caso es que Delphi oculta esta función de nosotros. Un ejemplo es la


posibilidad oculta de que un TStatusBar tenga algunos componentes como
TProgressBar en él.

• Propiedad
• En primer lugar, tenga en cuenta que un Formulario es el propietario
general de cualquier componente que resida en él (ubicado en el formulario
en el momento del diseño). Esto significa que cuando se destruye un
formulario, también se destruyen todos los componentes del formulario. Por
ejemplo, si tenemos una aplicación con más de un formulario cuando
llamamos al método Free o Release para un objeto de formulario, no
tenemos que preocuparnos de liberar explícitamente todos los objetos en
ese formulario, porque el formulario es el propietario de todos sus
componentes

• Todos los componentes que creamos, en diseño o tiempo de ejecución,


deben ser propiedad de otro componente. El propietario de un componente,
el valor de su propiedad Owner, se determina mediante un parámetro que
se pasa al Create constructor cuando se crea el componente.
• La única otra forma de reasignar el propietario es utilizar los métodos
InsertComponent / RemoveComponent durante el tiempo de ejecución. De
forma predeterminada, un formulario posee todos los componentes y, a su
vez, es propiedad de la Aplicación.

• Cuando utilizamos la palabra clave Self como el parámetro para el método


Create, el objeto que estamos creando es propiedad de la clase en la que
está contenido el método, que generalmente es un formulario Delphi.

• Si, por otro lado, hacemos que otro componente (no el formulario) sea el
propietario del componente, entonces hacemos que ese componente sea
responsable de deshacerse del objeto cuando se destruye.

• Al igual que cualquier otro componente de Delphi, el componente TFindFile


personalizado se puede crear, usar y destruir en tiempo de ejecución. Para
crear, usar y liberar un componente TFindFile en ejecución, puede usar el
siguiente fragmento de código:

• > usa FindFile; ... var FFile: TFindFile; procedimiento TForm1.InitializeData; begin //
form ("Self") es el propietario del componente // no hay Parent porque this // es un
componente invisible. FFile: = TFindFile.Create (Self); ... fin

• Nota: Como FFile se creó con un propietario (Form1), no necesitamos


hacer nada para liberar el componente; se liberará cuando se destruya el
propietario.

• Propiedad de componentes
• Todos los componentes que comparten el mismo Propietario están
disponibles como parte de la propiedad Componentes de ese Propietario.
El siguiente procedimiento se utiliza para borrar todos los componentes de
edición que están en el formulario:

• > procedimiento ClearEdits (AForm: TForm); var ii: Integer; begin for ii: =
0 a AForm.ComponentCount-1 do if (AForm.Components [ii] es TEdit) luego TEdit
(AForm.Components [ii]). Text: = ''; fin ;

• "Huérfanos"
• Algunos controles (como los controles ActiveX) están contenidos en
ventanas que no son de VCL en lugar de en un control principal. Para estos
controles, el valor de Parent es nulo y la
propiedad ParentWindow especifica la ventana padre que no es VCL. El
establecimiento de ParentWindow mueve el control para que esté contenido
en la ventana especificada. ParentWindow se establece automáticamente
cuando se crea un control utilizando el método CreateParented .

• La verdad es que en la mayoría de los casos no necesita preocuparse por


los padres y propietarios, pero cuando se trata de OOP y desarrollo de
componentes o cuando quiere llevar a Delphi un paso adelante, las
declaraciones en este artículo lo ayudarán a dar ese paso más rápido .

Integración de gráficos básicos en


aplicaciones Delphi
• by Zarko Gajic
• En la mayoría de las aplicaciones modernas de bases de datos, es
preferible o incluso necesario algún tipo de representación de datos
gráficos. Para tales fines, Delphi incluye varios componentes que tienen en
cuenta los datos: DBImage, DBChart, DecisionChart, etc. DBImage es una
extensión de un componente de imagen que muestra una imagen dentro de
un campo BLOB. El Capítulo 3 de este curso de la base de datos discutió la
visualización de imágenes (BMP, JPEG, etc.) dentro de una base de datos
de Access con ADO y Delphi.

• DBChart es una versión gráfica del componente TChart con reconocimiento


de datos.

• Nuestro objetivo en este capítulo es presentar el TDBChart


mostrándole cómo integrar algunos gráficos básicos en su aplicación
Delphi ADO.

• TeeChart
• El componente DBChart es una poderosa herramienta para crear tablas y
gráficos de bases de datos. No solo es poderoso, sino también complejo.
No exploraremos todas sus propiedades y métodos, por lo que deberá
experimentar con él para descubrir todo lo que es capaz de hacer y cómo
puede satisfacer mejor sus necesidades. Al utilizar DBChart con el motor de
gráficos TeeChart, puede hacer gráficos rápidamente para los datos en
conjuntos de datos sin necesidad de ningún código. TDBChart se conecta a
cualquier Delphi DataSource. Los conjuntos de registros ADO son
compatibles de forma nativa. No se requiere código adicional, o solo un
poco como verá. El editor de gráficos lo guiará a través de los pasos para
conectarse a sus datos; ni siquiera necesita ir al Inspector de Objetos.


Las bibliotecas de Runtime TeeChart se incluyen como parte de las
versiones Delphi Professional y Enterprise. TChart también está integrado
con QuickReport con un componente TChart personalizado en la paleta
QuickReport. Delphi Enterprise incluye un control DecisionChart en la
página Decision Cube de la paleta de componentes.
• Let's Chart! Preparar
• Nuestra tarea será crear un formulario Delphi simple con un gráfico lleno de
valores de una consulta de base de datos. Para seguir, crea una forma
Delphi de la siguiente manera:

• 1. Comience una nueva aplicación Delphi: se crea un formulario en blanco


por defecto.

• 2. Coloque el siguiente conjunto de componentes en el formulario:


ADOConnection, ADOQuery, DataSource, DBGrid y DBChart.

• 3. Utilice el Inspector de Objetos para conectar ADOQuery con


ADOConnection, DBGrid con DataSource con ADOQuery.

• 4. Configure un enlace con nuestra base de datos de demostración


(aboutdelphi.mdb) utilizando ConnectionString del componente
ADOConnection.

• 5. Seleccione el componente ADOQuery y asigne la siguiente cadena a la


propiedad SQL:

• SELECCIONE al cliente TOP 5. Empresa,


SUM (orders.itemstotal) AS SumItems,
COUNT (orders.orderno) AS NumOrders
DESDE el cliente, pedidos
DONDE customer.custno = orders.custno
GRUPO POR cliente.Empresa
ORDER BY SUM (orders.itemstotal) DESC

• Esta consulta utiliza dos tablas: pedidos y cliente. Ambas tablas se


importaron de la base de datos DBDemos (BDE / Paradox) a nuestra base
de datos de demostración (MS Access). Esta consulta da como resultado
un conjunto de registros con solo 5 registros. El primer campo es el nombre
de la empresa, el segundo (SumItems) es una suma de todos los pedidos
realizados por la empresa y el tercer campo (NumOrders) representa el
número de pedidos que realizó la empresa.

• Tenga en cuenta que esas dos tablas están vinculadas en una relación
maestro-detalle.

6. Cree una lista persistente de campos de base de datos. (Para invocar el


Editor de campos, haga doble clic en el componente ADOQuery. De forma
predeterminada, la lista de campos está vacía. Haga clic en Agregar para
abrir un cuadro de diálogo que enumere los campos recuperados por la
consulta (Compañía, NumOrders, SumItems). seleccionado. Seleccione
Aceptar.) Aunque no necesita un conjunto persistente de campos para
trabajar con un componente DBChart, lo crearemos ahora. Los motivos se
explicarán más adelante.

• 7. Establezca ADOQuery.Active en True en el Inspector de Objetos para ver


el conjunto resultante en tiempo de diseño.

Registre DLL y controles ActiveX desde


una aplicación Delphi
• by Zarko Gajic
• Una característica popular de Delphi es la implementación del proyecto de
una aplicación con un archivo ejecutable (exe) . Sin embargo, si los
controles DLL o ActiveX en su proyecto no están registrados en las
máquinas de los usuarios, se mostrará un "EOleSysError" en respuesta a la
ejecución del archivo exe. Para evitar esto, use la herramienta de línea de
comandos regsvr32.exe.

• Comando RegSvr32.exe
• Manualmente, el uso de regsvr32.exe (Windows.Start - Run) registrará y
anulará el registro de DLL autoregistro y controles ActiveX en un sistema.

• Regsvr32.exe indica al sistema que intente cargar el componente y llamar a


su función DLLSelfRegister. Si este intento es exitoso, Regsvr32.exe
muestra un cuadro de diálogo que indica el éxito.

• RegSvr32.exe tiene las siguientes opciones de línea de comandos:

• Regsvr32 [/ u] [/ s] [/ n] [/ i [: cmdline]] dllname / s - Silencioso; no mostrar cuadros


de mensajes / u - Anular el registro del servidor / i - Llamar a DllInstall pasándole
una [cmdline] opcional; cuando se usa con / u llama a dll uninstall / n - no llame a
DllRegisterServer; esta opción debe usarse con / i

• Llamar a RegSvr32.exe dentro del código Delphi

• Para llamar a la herramienta regsvr32 dentro del código Delphi, use la


función "RegisterOCX" para ejecutar un archivo y esperar a que finalice la
ejecución.

• Así es como podría verse el procedimiento 'RegisterOCX':

• procedimiento RegisterOCX; tipo TRegFunc = function :


HResult; stdcall ; var ARegFunc: TRegFunc; aHandle: Thandle;
ocxPath: cadena ; begin try ocxPath: = ExtractFilePath (Application.ExeName) +
'Flash.ocx'; aHandle: = LoadLibrary (PChar (ocxPath)); if aHandle
0 entonces comienza ARegFunc: = GetProcAddress (aHandle,
'DllRegisterServer'); si se le asigna (ARegFunc), entonces comienza ExecAndWait
('regsvr32', '/ s' + ocxPath); fin ; FreeLibrary (aHandle); fin; excepto ShowMessage
(Formato ('No se puede registrar% s', [ocxPath])); fin ; fin ;

• Nota: la variable ocxPath apunta a Macromedia OCX 'Flash.ocx'.

• Para poder registrarse, un OCX debe implementar la función


DllRegisterServer para crear entradas de registro para todas las clases
dentro del control. No se preocupe por la función DllRegisterServer, solo
asegúrese de que esté allí. En aras de la simplicidad, se presume que el
OCX está ubicado en la misma carpeta donde está la aplicación.

• La línea ExecAndWait en el código anterior llama a la herramienta regsvr32


pasando el interruptor "/ s" junto con la ruta completa al OCX. La función es
ExecAndWait.

• usa shellapi; ... función ExecAndWait ( const ExecuteFile, ParamString: string ):


boolean; var SEInfo: TShellExecuteInfo; ExitCode: DWORD; comenzar FillChar
(SEInfo, SizeOf (SEInfo), 0); SEInfo.cbSize: = SizeOf
(TShellExecuteInfo); con SEInfo comienzan fMask: =
SEE_MASK_NOCLOSEPROCESS; Wnd: = Application.Handle; lpFile: = PChar
(ExecuteFile); lpParameters: = PChar (ParamString); nMostrar: =
SW_HIDE; e nd; si ShellExecuteEx (@SEInfo)
a continuación, repita Application.ProcessMessages; GetExitCodeProcess
(SEInfo.hProcess, ExitCode); until (ExitCode STILL_ACTIVE) o
Application.Terminated; Resultado: = Verdadero; end else Result: = False; fin ;

• La función ExecAndWait utiliza la llamada ShellExecuteEx API para


ejecutar un archivo en un sistema. Para obtener más ejemplos de cómo
ejecutar cualquier archivo desde Delphi, consulte cómo ejecutar y ejecutar
aplicaciones y archivos desde el código Delphi .

• Flash.ocx Inside Delphi Exe


• Si es necesario registrar un control ActiveX en el equipo del usuario,
asegúrese de que el usuario tenga el OCX que el programa requiere al
colocar todo el ActiveX (o DLL) dentro del archivo ejecutable de la
aplicación como un recurso.

• Cuando el OCX se almacena dentro del exe, es fácil de extraer, guardar en


el disco y llamar al procedimiento RegisterOCX.
SQL en Delphi
• by Zarko Gajic

SQL (Structured Query Language) es un lenguaje estandarizado para definir y


manipular datos en una base de datos relacional. De acuerdo con el modelo
relacional de datos, la base de datos se percibe como un conjunto de tablas, las
relaciones se representan mediante valores en tablas y los datos se recuperan
especificando una tabla de resultados que se puede derivar de una o más tablas
base. Las consultas toman la forma de un lenguaje de comandos que le
permite seleccionar, insertar, actualizar, averiguar la ubicación de los datos, etc.

En Delphi ... TQuery

Si vas a utilizar SQL en tus aplicaciones, te familiarizarás mucho con el


componente TQuery . Delphi permite que sus aplicaciones utilicen la sintaxis SQL
directamente a través del componente TQuery para acceder a datos de tablas
Paradox y dBase (utilizando SQL local - subconjunto de SQL estándar ANSI),
bases de datos en el servidor InterBase local y bases de datos en servidores
remotos de bases de datos.
Delphi también admite consultas heterogéneas contra más de un servidor o tipo de
tabla (por ejemplo, datos de una tabla Oracle y una tabla Paradox) .TQuery tiene
una propiedad llamada SQL , que se usa para almacenar la declaración SQL.

TQuery encapsula una o más sentencias SQL, las ejecuta y proporciona métodos
mediante los cuales podemos manipular los resultados. Las consultas se pueden
dividir en dos categorías: las que producen conjuntos de resultados (como una
instrucción SELECT ) y las que no (como una instrucción UPDATE o INSERT ).

Use TQuery.Open para ejecutar una consulta que produzca un conjunto de


resultados; utilice TQuery.ExecSQL para ejecutar consultas que no producen
conjuntos de resultados.

Las sentencias de SQL pueden ser estáticas o dinámicas , es decir, pueden


establecerse en tiempo de diseño o incluir parámetros ( TQuery.Params ) que
varían en tiempo de ejecución. El uso de consultas parametrizadas es muy
flexible, porque puede cambiar la vista de un usuario y el acceso a los datos sobre
la marcha en tiempo de ejecución.

Todas las sentencias SQL ejecutables deben prepararse antes de que puedan
ejecutarse. El resultado de la preparación es la forma ejecutable u operacional de
la declaración. El método de preparación de una declaración SQL y la persistencia
de su forma operacional distinguen SQL estático de SQL dinámico. En el momento
del diseño, una consulta se prepara y ejecuta automáticamente cuando establece
la propiedad Activo del componente de consulta en True. En tiempo de ejecución,
se prepara una consulta con una llamada a Preparar, y se ejecuta cuando la
aplicación llama a los métodos Open o ExecSQL del componente.

Un TQuery puede devolver dos tipos de conjuntos de resultados: "en vivo " como
con el componente TTable (los usuarios pueden editar datos con controles de
datos, y cuando se envía una llamada a los cambios se envían a la base de
datos), " solo lectura " para fines de visualización solamente. Para solicitar un
conjunto de resultados en vivo, establezca la propiedad RequestLive de un
componente de consulta en True y tenga en cuenta que la declaración SQL debe
cumplir con algunos requisitos específicos (sin ORDER BY, SUM, AVG, etc.)

Una consulta se comporta de muchas maneras muy parecida a un filtro de tabla, y


de alguna manera una consulta es incluso más poderosa que un filtro porque le
permite acceder a:

▪ más de una tabla a la vez ("join" en SQL),


▪ un subconjunto específico de filas y columnas de su (s) tabla (s) subyacente (s),
en lugar de devolver siempre todas ellas.

Ejemplo simple

Ahora veamos algunos SQL en acción. Aunque podríamos usar el asistente de


formularios de base de datos para crear algunos ejemplos de SQL para este
ejemplo, lo haremos manualmente, paso a paso:

1. Coloque un TQuery, TDataSource, TDBGrid, TEdit y un componente TButton en


el formulario principal.
2. Establezca la propiedad DataSet del componente TDataSource en Query1.
3. Establezca la propiedad DataSource del componente TDBGrid en DataSource1.
4. Establezca la propiedad DatabaseName del componente TQuery en
DBDEMOS.
5. Haga doble clic en la propiedad SQL de un TQuery para asignarle la
declaración SQL.
6. Para que la cuadrícula muestre los datos en tiempo de diseño, cambie la
propiedad Activa del componente de QQuery a True.
La cuadrícula muestra datos de la tabla Employee.db en tres columnas
(FirstName, LastName, Salary) incluso si Emplyee.db tiene 7 campos, y el
conjunto de resultados está restringido a aquellos registros donde FirstName
comienza con 'R'.

7. Ahora asigne el siguiente código al evento OnClick del Button1.


procedure TForm1.Button1Click (Sender: TObject); comenzar Query1.Close; {cerrar la consulta} // asignar nueva exp
SQL Query1.SQL.Clear; Query1.SQL.Add ('Seleccionar EmpNo, Nombre, Apellido'); Query1.SQL.Add ('FROM Employee
Query1.SQL.Add ('WHERE Salary>' + Edit1.Text); Query1.RequestLive: = verdadero; Query1.Open; {open query + displ

8. Ejecute su aplicación. Cuando hace clic en el botón (siempre que Edit 1 tenga
un valor de moneda válido en él), la grilla mostrará los campos EmpNo, FirstName
y LastName para todos los registros donde Salario sea mayor que el valor de
moneda especificado.

En este ejemplo creamos una declaración SQL estática simple con un conjunto de
resultados en vivo (no hemos cambiado ninguno de los registros visualizados) solo
para propósitos de visualización.

Cómo mover y cambiar el tamaño de los


controles en tiempo de ejecución (en
aplicaciones Delphi)
• by Zarko Gajic

A continuación, le mostramos cómo habilitar los controles de arrastre y cambio de


tamaño (en un formulario Delphi) con un mouse, mientras la aplicación se está
ejecutando.

Editor de formularios en tiempo de ejecución

Una vez que coloca un control (componente visual) en el formulario, puede ajustar
su posición, tamaño y otras propiedades de tiempo de diseño. Sin embargo, hay
situaciones en las que tiene que permitir que un usuario de su aplicación cambie la
posición de los controles de formulario y cambie su tamaño, en tiempo de
ejecución.

Para habilitar el movimiento del usuario en tiempo de ejecución y cambiar el


tamaño de los controles en un formulario con un mouse, tres eventos relacionados
con el mouse necesitan un manejo especial: OnMouseDown, OnMouseMove y
OnMouseUp.

En teoría, supongamos que quiere permitir que un usuario mueva (y cambie el


tamaño) un control de botón, con un mouse, en tiempo de ejecución. En primer
lugar, maneja el evento OnMouseDown para permitir que el usuario "agarre" el
botón. A continuación, el evento OnMouseMove debe reposicionar (mover,
arrastrar) el botón. Finalmente, OnMouseUp debería finalizar la operación de
movimiento.

Arrastrar y cambiar el tamaño de los controles de formulario en la práctica

En primer lugar, suelte varios controles en un formulario. Tener un CheckBox para


habilitar o deshabilitar mover y cambiar el tamaño de los controles en tiempo de
ejecución.

A continuación, defina tres procedimientos (en la sección de interfaz de la


declaración del formulario) que manejarán los eventos del mouse como se
describió anteriormente:

tipo TForm1 = clase (TForm) ... procedimiento ControlMouseDown (Sender: TObject; Botón: TMouseButton; Shift: T
Integer); procedimiento ControlMouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer); procedimiento Contr
(Sender: TObject; Botón: TMouseButton; Shift: TShiftState; X, Y: Integer); private inReposition: boolean; oldPos: TPoin

Nota: se requieren dos variables de nivel de formulario para marcar si el


movimiento de control se está llevando a cabo (en Reposición ) y para almacenar
la posición anterior de control ( puntos anteriores ).

En el evento OnLoad del formulario, asigne procedimientos de manejo de eventos


del mouse a los eventos correspondientes (para aquellos controles que desea que
sean arrastrables / redimensionables):

procedure TForm1.FormCreate (Sender: TObject); begin Button1.OnMouseDown: = ControlMouseDown; Button1.On


ControlMouseMove; Button1.OnMouseUp: = ControlMouseUp; Edit1.OnMouseDown: = ControlMouseDown; Edit1.O
ControlMouseMove; Edit1.OnMouseUp: = ControlMouseUp; Panel1.OnMouseDown: = ControlMouseDown; Panel1.O
ControlMouseMove; Panel1.OnMouseUp: = ControlMouseUp; Button2.OnMouseDown: = ControlMouseDown; Butto
= ControlMouseMove; Button2.OnMouseUp: = ControlMouseUp; fin ; (* FormCreate *)

Nota: el código anterior habilita la reposición en tiempo de ejecución de Button1,


Edit1, Panel1 y Button2.

Finalmente, aquí está el código mágico:

procedure TForm1.ControlMouseDown (Sender: TObject; Botón: TMouseButton; Shift: TShiftState; X, Y:


Integer); begin if (chkPositionRunTime.Checked) AND (El remitente es TWinControl) y luego comienza en Repositio
SetCapture (TWinControl (Sender) .Handle); GetCursorPos (oldPos); fin ; fin ; (* ControlMouseDown *)
ControlMouseDown en resumen: una vez que un usuario presiona un botón del
mouse sobre un control, si la reposición en tiempo de ejecución está habilitada
(checkbox chkPositionRunTime is Checked) y el control que recibió el mouse
incluso se deriva de TWinControl, marque que la reposición del control está
teniendo lugar ( inReposition: = True) y asegúrese de que se capture todo el
procesamiento del mouse para el control, para evitar que se procesen los eventos
de "clic" predeterminados.

procedure TForm1.ControlMouseMove (Sender: TObject; Shift: TShiftState; X, Y: Integer); const minWidth = 20; minH
20; var newPos: TPoint; frmPoint: TPoint; comience si inReposition luego comience con TWinControl
(Sender) comience GetCursorPos (newPos); si ssShift en Shift entonces comienza // redimensiona Screen.Cursor: =
frmPoint: = ScreenToClient (Mouse.CursorPos); si frmPoint.X> minWidth then Ancho: = frmPoint.X; si frmPoint.Y>
minHeight, entonces Height: = frmPoint.Y; end else // move begin Screen.Cursor: = crSize; Izquierda: = Izquierda - o
newPos.X; Arriba: = Superior - viejoPos.Y + nuevoPos.Y; oldPos: = newPos; fin ; fin ; fin ; fin ; (* ControlMouseMove *

ControlMouseMove en resumen: cambie el cursor de la pantalla para reflejar la


operación: si se presiona la tecla Shift, permita cambiar el tamaño del control, o
simplemente mueva el control a una nueva posición (hacia donde se dirige el
mouse). Nota: las constantes minWidth y minHeight proporcionan una especie de
restricción de tamaño (ancho y altura mínima de control).

Cuando se suelta el botón del mouse, se ha terminado de arrastrar o


redimensionar:

procedure TForm1.ControlMouseUp (Sender: TObject; Botón: TMouseButton; Shift: TShiftState; X, Y: Integer); comien
en Reposición luego comience Screen.Cursor: = crDefault; ReleaseCapture; inReposition: = False; fin ; fin ; (* Contro

ControlMouseUp en resumen: cuando un usuario ha terminado de mover (o


cambiar el tamaño del control), suelte la captura del mouse (para habilitar el
procesamiento predeterminado de clics) y marque que la reposición ha finalizado.

Y eso lo hace! Descargue la aplicación de muestra y pruébelo usted mismo.

Nota: Otra forma de mover controles en tiempo de ejecución es utilizar las propiedades y métodos relacionados de
de Delphi (Modo Drag, OnDragDrop, DragOver, BeginDrag, etc.). Arrastrar y soltar se puede usar para permitir a los
elementos de un control, como un cuadro de lista o una vista de árbol, a otro.

¿Cómo recordar la posición y el tamaño de control?


Si permite que un usuario mueva y cambie el tamaño de los controles de formulario, debe asegurarse de que la ubi
se guarde de alguna manera cuando se cierra el formulario y de que se restaura la posición de cada control cuando
formulario. A continuación, le mostramos cómo almacenar las propiedades Left, Top, Width y Height, para cada con
formulario, en un archivo INI .

¿Qué tal 8 tamaños de manijas?


Cuando permite que un usuario mueva y cambie el tamaño de los controles en el formulario Delphi, en tiempo de ej
mouse, para imitar completamente el entorno de tiempo de diseño, debe agregar ocho controles de tamaño al contr
de tamaño.

Cómo almacenar datos de registro en un


campo BLOB en Delphi
• by Zarko Gajic

En Delphi, un tipo de datos de registro es un tipo especial de tipo de datos definido


por el usuario. Un registro es un contenedor para una mezcla de variables
relacionadas de diversos tipos, llamadas campos, recopilados en un tipo.

En aplicaciones de bases de datos, los datos se almacenan en campos de varios


tipos: entero, cadena, bit (booleano), etc. Aunque la mayoría de los datos se
pueden representar con tipos de datos simples, hay situaciones en las que
necesita almacenar imágenes, documentos enriquecidos o datos personalizados.
tipos en una base de datos.

Cuando este sea el caso, usará el tipo de datos BLOB (Objeto grande binario)
("memo", "ntext", "image", etc. - el nombre del tipo de datos depende de la base de
datos con la que trabaja).

Registrar como Blob


A continuación se explica cómo almacenar (y recuperar ) un valor
de registro (estructura) en un campo de blob en una base de datos.

TUser = grabar ...


Supongamos que ha definido su tipo de registro personalizado como:

> TUser = registro lleno Nombre: cadena [50]; CanAsk: booleano; NumberOfQuestions:
entero; fin ;

"Record.SaveAsBlob"
Para insertar una nueva fila (registro de base de datos) en una tabla de base de
datos con un campo BLOB llamado "datos", use el siguiente código:

> var Usuario: TUser; blobF: TBlobField; bs: TStream; begin User.Name: =
edName.Text; User.NumberOfQuestions: = StrToInt (edNOQ.Text); User.CanAsk: =
chkCanAsk.Checked; myTable.Insert; blobF: = myTable.FieldByName
('datos') como TBlobField; bs: = myTable.CreateBlobStream (blobF, bmWrite); try bs.Write
(Usuario, SizeOf (Usuario)); finalmente bs.Free; fin ; fin ;

En el código de arriba:

▪ "myTable" es el nombre del componente TDataSet que está utilizando (TTable, TQuery,
ADOTable, TClientDataSet, etc.).
▪ El nombre del campo blob es "datos".
▪ La variable "Usuario" (TUser registro) se completa utilizando 2 cuadros de edición
("edName" y "edNOQ") y una casilla de verificación ("chkCanAsk")
▪ El método CreateBlobStream crea un objeto TStream para escribir en el campo blob.
"Record.ReadFromBlob"
Una vez que haya guardado los datos del registro (TUser) en un campo de tipo de
blob, aquí se explica cómo "transformar" los datos binarios en un valor de TUser:

> var Usuario: TUser; blobF: TBlobField; bs: TStream; comience si myTable.FieldByName
('data'). IsBlob luego comienza blobF: = DataSet.FieldByName ('data') como TBlobField; bs:
= myTable.CreateBlobStream (blobF, bmRead); intente bs.Read (usuario, tamaño de
(TUser)); finalmente bs.Free; fin ; fin ; edName.Text: = User.Name; edNOQ.Text: = IntToStr
(User.NumberOfQuestions); chkCanAsk.Checked: = User.CanAsk; fin ;

Nota: el código anterior debe ir dentro del controlador de eventos "OnAfterScroll"


del conjunto de datos myTable.

Eso es. Asegúrese de descargar el código de muestra Record2Blob.

Construir la cadena de conexión de la


base de datos dinámicamente en tiempo
de ejecución
• by Zarko Gajic
• Una vez que haya terminado su solución de base de datos Delphi, el paso
final es desplegarla con éxito en la computadora del usuario.

• ConnectionString On-The-Fly
• Si estaba utilizando componentes dbGo (ADO), la
propiedad ConnectionString de TADOConnection especifica la información
de conexión para el almacén de datos.
• Obviamente, al crear aplicaciones de bases de datos que se ejecutarán en
varias máquinas, la conexión a la fuente de datos no debe estar codificada
en el ejecutable.

• En otras palabras, la base de datos puede estar ubicada en cualquier lugar


de la computadora del usuario (o en alguna otra computadora en una red):
la cadena de conexión utilizada en el objeto TDOConnection debe crearse
en tiempo de ejecución. Uno de los lugares sugeridos para almacenar los
parámetros de la cadena de conexión es el Registro de Windows (o puede
decidir usar los archivos INI "simples").

• En general, para crear la cadena de conexión en tiempo de ejecución, debe


a) coloque la ruta completa a la base de datos en el Registro; y
b) cada vez que inicie su aplicación, lea la información del Registro, "cree"
ConnectionString y "abra" la ADOConnection.

• Base de datos ... ¡Conecta!


• Para ayudarlo a comprender el proceso, he creado una aplicación
"esqueleto" de muestra que consta de un formulario (formulario principal de
la aplicación) y un módulo de datos. Los módulos de datos de Delphi
proporcionan una herramienta de organización conveniente que se utiliza
para aislar las partes de la aplicación que manejan la conectividad de la
base de datos y las reglas comerciales.

• El evento OnCreate del Módulo de datos es donde coloca el código para


construir dinámicamente ConnectionString y conectarse a la base de datos.

procedimiento TDM.DataModuleCreate (Sender: TObject); comience si DBConnect luego ShowMessage ('Conectad


datos!') else ShowMessage ('NO conectado a la base de datos!'); fin ;

• Nota: El nombre del Módulo de datos es "DM". El nombre del componente


TDOConnection es "AdoConn".

• La función DBConnect hace el trabajo real de conectarse a la base de


datos, aquí está el código:

función TDM.DBConnect: boolean; var conStr: cadena; ServerName, DBName: cadena; begin ServerName: = ReadRe
('DataSource'); DBName: = ReadRegistry ('DataCatalog'); conStr: = 'Proveedor = sqloledb;' + 'Data Source =' + Serve
'Initial Catalog =' + DBName + ';' + 'User Id = myUser; Password = myPasword'; Resultado: = falso AdoConn.Close;
AdoConn.ConnectionString: = conStr; AdoConn.LoginPrompt: = Falso; if ( NO AdoConn.Connected) entonces prueb
Resultado: = Verdadero; excepto en E: Excepción do begin MessageDlg ('Hubo un error al conectarse a la base de d
# 10 + e.Message, mtError, [mbOk], 0); if NOT TDatabasePromptForm.Execute (ServerName, DBName) then Result: =
false else begin WriteRegistry ('DataSource', ServerName); WriteRegistry ('DataCatalog', DBName); // recuperar esta
= DBConnect; fin ; fin ; fin ; fin ; // DBConnect

• La función DBConnect se conecta a la base de datos del servidor MS SQL -


ConnectionString se construye utilizando la variable local connStr .

• El nombre del servidor de la base de datos se almacena en la


variable ServerName , el nombre de la base de datos se mantiene en la
variable DBName . La función comienza leyendo esos dos valores del
registro (usando el procedimiento ReadRegistry () personalizado ). Una vez
que ensambla ConnectionString, simplemente
llamamos al método AdoConn.Open . Si esta llamada devuelve
"verdadero", nos hemos conectado con éxito a la base de datos.

• Nota: Dado que estamos aprobando información de inicio de sesión


explícitamente a través de ConnectionString, dado que el módulo de datos
se creó antes que el formulario principal, puede llamar de manera segura a
los métodos desde el módulo de datos en el evento OnCreate de
MainForm. La propiedad LoginPrompt se establece en false para evitar un
diálogo de inicio de sesión innecesario.

• La "diversión" comienza si ocurre una excepción. Si bien puede haber


muchas razones para que falle el método Open, supongamos que el
nombre del servidor o el nombre de la base de datos son incorrectos.
Si este es el caso, le daremos la oportunidad al usuario de especificar los
parámetros correctos mostrando un formulario de diálogo personalizado.
La aplicación de ejemplo también contiene un formulario adicional
(DatabasePromptForm) que permite al usuario especificar el servidor y el
nombre de la base de datos para el componente Connection. Esta forma
simple solo proporciona dos cuadros de edición, si desea proporcionar una
interfaz más amigable para el usuario, puede agregar dos ComboBoxes y
completarlos enumerando servidores SQL disponibles y recuperando bases
de datos en un servidor SQL.

• El formulario DatabasePrompt proporciona un método de


clase personalizado llamado Execute que acepta dos parámetros variables
(var): ServerName y DBName.

• Con los "nuevos" datos proporcionados por un usuario (servidor y nombre


de la base de datos) simplemente llamamos a la función DBConnect ()
nuevamente (recursivamente). Por supuesto, la información se almacena
primero en el Registro (utilizando otro método personalizado:
WriteRegistry).
• Asegúrese de que DataModule sea el primer "formulario" creado.
• Si intenta crear este proyecto simple por su cuenta, es posible que
experimente excepciones de Infracción de acceso cuando ejecuta la
aplicación.
De forma predeterminada, el primer formulario agregado a la aplicación se
convierte en MainForm (el primero creado). Cuando agrega un módulo de
datos a la aplicación, el módulo de datos se agrega a la lista de "creación
automática de formularios" como el formulario que se crea después del
formulario principal.
Ahora, si intenta llamar a cualquiera de las propiedades o métodos del
Módulo de datos en el evento OnCreate de MainForm, obtendrá una
excepción de Infracción de acceso, ya que el módulo de datos aún no se ha
creado.


Para resolver este problema, debe cambiar manualmente el orden de
creación del módulo de datos y configurarlo para que sea el primer
formulario que la aplicación cree (ya sea utilizando el cuadro de diálogo
Proyecto-Propiedades o editando el archivo fuente de Proyectos ).

• Como el módulo de datos se creó antes que el formulario principal, puede


llamar de manera segura a los métodos desde el módulo de datos en el
evento OnCreate de MainForm.

Formateo de líneas en Rich Edit


utilizando SelText y SelStart de Delphi
• by Zarko Gajic
• Agregue líneas formateadas (color, estilo, fuente) a TRichEdit

• El control TRichEdit Delphi es un contenedor para un control de edición de


texto enriquecido de Windows. Puede usar un control Rich Edit para
visualizar y editar archivos RTF.

• Si bien puede crear una agradable interfaz de usuario "alrededor" del


control Rich Edit con los botones de la barra de herramientas para
establecer y cambiar atributos de visualización de texto, agregar líneas
formateadas a Rich Edit mediante programación es bastante engorroso,
como verá.

• Cómo agregar líneas formateadas a Rich Edit


• Para crear texto en negrita a partir de una selección de texto que se
muestra en el control Rich Edit, en tiempo de ejecución, debe crear una
sección de texto y luego establecer las propiedades de la selección
en SelAttributes .
• Sin embargo, ¿qué ocurre si no se trata de una selección de texto y, en su
lugar, desea agregar (adjuntar) texto formateado a un control Rich Edit?
Puede pensar que la propiedad Líneas se puede usar para agregar texto en
negrita o color a Rich Edit. Sin embargo, Lines es un TStrings simple y solo
aceptará texto sin formato.

• No te rindas, por supuesto, hay una solución.

• Mire este ejemplo para obtener ayuda:

• > // richEdit1 de tipo TRichEdit con richEdit1 do begin // move caret to end SelStart:
= GetTextLen; // agrega una línea sin formato SelText: = 'Esta es la primera línea' +
# 13 # 10; // agrega texto de fuente normal SelText: = 'Líneas formateadas en
RichEdit' + # 13 # 10; // texto más grande SelAttributes.Size: = 13; // agrega negrita
+ rojo SelAttributes.Style: = [fsBold]; SelAttributes.Color: = clRed; SelText: = 'Acerca
de'; // solo negrita SelAttributes.Color: = clWindowText; SelText: = 'Delphi'; // agregar
cursiva + azul SelAttributes.Style: = [fsItalic]; SelAttributes.Color: = clBlue; SelText: =
'Programación'; // nueva línea SelText: = # 13 # 10; // agrega normal otra
vez SelAttributes.Size: = 8; SelAttributes.Color: = clGreen; SelText: = 'pensar en el
procedimiento personalizado AddFormattedLine ...'; fin ;

• Para comenzar, mueva el cursor al final del texto en Rich Edit. Luego,
aplique el formateo antes de agregar el nuevo texto.

Implementación en Item Click / Double


Click para TListView
• by Zarko Gajic

ListView.OnItemClick / OnItemDblClick

El control TListView de Delphi muestra una lista de elementos en columnas con


encabezados de columnas y subtemas, o vertical u horizontalmente, con iconos
pequeños o grandes.

Al igual que la mayoría de los controles Delphi, TListView expone los


eventos OnClick y OnDblClick (OnDoubleClick).

Desafortunadamente, si necesita saber en qué elemento se hizo clic o se hizo


doble clic, no puede simplemente manejar los eventos OnClick / OnDblClick para
obtener el elemento al que se hace clic.

El evento OnClick (OnDblClick) para TListView se activa cada vez que el usuario
hace clic en el control, es decir, cada vez que el "clic" ocurre en algún lugar dentro
del área del cliente del control .
El usuario puede hacer clic dentro de la vista de lista, PERO "perder" alguno de
los elementos. Además, dado que la vista de lista puede cambiar su visualización
dependiendo de la propiedad ViewStyle, el usuario podría haber hecho clic en un
elemento, en un título de elemento, en un icono de elemento, "en ninguna parte",
en un icono de estado de elemento, etc.

Nota: la propiedad ViewStyle determina cómo se muestran los elementos en la


vista de lista: los elementos se pueden mostrar como un conjunto de iconos
movibles o como columnas de texto.

ListView.On Item Click & ListView.On Item Double Click


Para poder ubicar el elemento cliqueado (si hay uno) cuando se activa el evento OnClick
para la vista de lista, debe determinar qué elementos de la vista de lista se encuentran bajo
el punto especificado por los parámetros X e Y, que es el ubicación del mouse en el
momento del "clic".

La función GetHitTestInfoAt de TListiew devuelve información sobre el punto


especificado en el área de cliente de la vista de lista.

Para asegurarse de que se hizo clic en el elemento (o se hizo doble clic), debe
llamar al GetHitTestInfoAt y reaccionar solo si el evento click se produjo en un
elemento real.

Aquí hay una implementación de ejemplo del evento OnDblClick de ListView1:

> // maneja el procedimiento de Click Double Click TForm de


ListView1. ListView1 DblClick (Sender: TObject); var hts: THitTests; ht:
THitTest; sht: cadena ; ListViewCursosPos: TPoint; selectedItem: TListItem; begin // posición
del cursor del mouse relacionado con ListView ListViewCursosPos: = ListView1.ScreenToClient
(Mouse.CursorPos); // haz doble clic donde? hts: = ListView1.GetHitTestInfoAt
(ListViewCursosPos.X, ListViewCursosPos.Y); // prueba de golpe "debug" Leyenda: =
''; para ht en hts do begin sht: = GetEnumName (TypeInfo (THitTest), Integer (ht)); Leyenda:
= Formato ('% s% s |', [Caption, sht]); fin ; // ubicar el elemento de doble clic si hts <=
[htOnIcon, htOnItem, htOnLabel, htOnStateIcon] luego comienza selectedItem: =
ListView1.Selected; // hacer algo con el elemento doble clic! Título: = Formato ('DblClcked:%
s', [selectedItem.Caption]); fin ; fin ;

En el controlador de eventos OnDblClick (o OnClick), lea la función


GetHitTestInfoAt al proporcionarle la ubicación del mouse "dentro" del control.
Para obtener la posición del mouse relacionada con la vista de lista, la función
ScreenToClient se usa para convertir un punto (mouse X e Y) en coordenadas de
pantalla en coordenadas locales, o del área del cliente.

GetHitTestInfoAt devuelve un valor del tipo THitTests . THitTests es un conjunto


de valores enumerados de THitTest .
Los valores de enumeración de THitTest, con su descripción, son:

▪ htAbove - sobre el área del cliente.


▪ htBelow : debajo del área del cliente.
▪ htNowhere - dentro del control, pero no en un elemento.
▪ htOnItem - en un elemento, su texto o su mapa de bits.
▪ htOnButton - en un botón.
▪ htOnIcon - en un icono.
▪ htOnIndent : en el área sangrada de un elemento.
▪ htOnLabel - en una etiqueta.
▪ htOnRight - en el lado derecho de un artículo.
▪ htOnStateIcon : en un icono de estado o mapa de bits asociado a un elemento.
▪ htToLeft : a la izquierda del área del cliente.
▪ htToRight - a la derecha del área del cliente.
Si el resultado de la llamada a GetHitTestInfoAt es un subconjunto (establece
Delphi!) De [htOnIcon, htOnItem, htOnLabel, htOnStateIcon], puede estar seguro
de que el usuario hizo clic en el elemento (o en su ícono de icono / estado).

Finalmente, si lo anterior es verdadero, lea la propiedad Seleccionado de la vista


de lista, devuelve el primer elemento seleccionado (si se puede seleccionar el
número múltiple) en la vista de lista.

Haga algo con el elemento cliqueado / doble clic / seleccionado ...

Asegúrese de descargar el código fuente completo para explorar el código y


aprender al adoptarlo :)

Use archivos de Adobe Acrobat (PDF) en


una aplicación Delphi
• by Zarko Gajic

Delphi admite la visualización de archivos PDF de Adobe desde una aplicación.


Siempre que tenga Adobe Reader instalado, su PC tendrá automáticamente el
control ActiveX relevante que necesitará para crear un componente que pueda
colocar en un formulario Delphi.

Dificultad: Fácil
Tiempo requerido: 5 minutos

Así es cómo:

1. Inicie Delphi y seleccione Componente | Importar control ActiveX ...


2. Busque el control "Acrobat Control for ActiveX (Version xx)" y haga clic
en Instalar .

1. Seleccione la ubicación de la paleta de componentes en la que aparecerá la


biblioteca seleccionada. Haga clic en Instalar .
2. Seleccione un paquete donde se debe instalar el nuevo componente o cree un
nuevo paquete para el nuevo control TPdf.
3. Haga clic en Aceptar .
4. Delphi le preguntará si desea reconstruir el paquete modificado / nuevo. Haga
clic en Sí .
5. Después de compilar el paquete, Delphi le mostrará un mensaje que dice que el
nuevo componente TPdf se registró y ya está disponible como parte de la VCL.
6. Cierre la ventana de detalles del paquete, lo que permite a Delphi guardar los
cambios en él.
7. El componente ahora está disponible en la pestaña ActiveX (si no modificó esta
configuración en el paso 4).
8. Coloque el componente TPdf en un formulario y luego selecciónelo.
9. Usando el inspector de objetos, establezca la propiedad src en el nombre de un
archivo PDF existente en su sistema. Ahora todo lo que tiene que hacer es
cambiar el tamaño del componente y leer el archivo PDF desde su aplicación
Delphi.
Consejos:

▪ El control Adobe ActiveX se instala automáticamente cuando instala Adobe


Reader.

▪ El paso 11 se puede completar durante el tiempo de ejecución, por lo que


puede abrir y cerrar archivos mediante programación, así como cambiar el
tamaño del control.
Establecer una leyenda de líneas
múltiples para una etiqueta (en tiempo
de diseño)
• by Zarko Gajic

Un componente TLabel Delphi tiene una propiedad WordWrap que puede


establecer en verdadero para que el texto de la propiedad Título aparezca
envuelto (multilineado) cuando es demasiado largo para el ancho de la etiqueta.

Además, en tiempo de ejecución, puede usar la siguiente tarea para especificar


varias líneas de texto para una etiqueta:

Label1.Caption: = 'Primera línea' + # 13 # 10 + 'Segunda línea';

Ver: "¿Qué significa # 13 # 10, en el código Delphi?"

Sin embargo, * no puede * especificar texto de varias líneas para un TLabel en


tiempo de diseño, utilizando el Inspector de Objetos.

Un truco para agregar más líneas de texto para una propiedad Caption de TLabel,
en tiempo de diseño, es editar el archivo .DFM del Formulario directamente. Así es
cómo:

1. Coloque un TLabel en un formulario


2. Haga clic derecho en el formulario para activar el menú emergente
3. Seleccione "Ver como texto"
4. Ubique la sección "objeto Label1: TLabel"
5. Cambia la línea "Caption = 'Label1'" a:
6. Leyenda = 'Etiqueta1' + # 13 # 10 + 'Segunda línea'
7. Haga clic derecho en el código para activar la ventana emergente, nuevamente
8. Seleccione "Ver como formulario"
9. ¡Trabajo hecho! ¡TLabel con múltiples líneas de texto, en tiempo de diseño!
Navegador de consejos de Delphi:
» Descripción y uso de tipos de datos de matriz en Delphi
« Cómo configurar el dbGo (ADO) ConnectionString para la base de datos mySQL
¿Qué significa # 13 # 10, en el código
Delphi?
• by Zarko Gajic

Las cadenas crípticas como "# 13 # 10" aparecen regularmente dentro del código
fuente de Delphi. Sin embargo, estas cadenas no son un galimatías al azar; sirven
un propósito esencial para el diseño del texto.

Una cadena de control es una secuencia de uno o más caracteres de control, cada
uno de los cuales consiste en el símbolo # seguido de una constante entera sin
signo de 0 a 255 (decimal o hexadecimal) y denota el
carácter ASCII correspondiente.

Cuando desee, por ejemplo, asignar una cadena de dos líneas a una propiedad
Caption (de un control TLabel), puede usar el siguiente pseudocódigo:

> Label1.Caption: = 'Primera línea' + # 13 # 10 + 'Segunda línea';

La pieza "# 13 # 10" representa una combinación de retorno de carro + avance de


línea. El "# 13" es el equivalente ASCII del valor CR (retorno de carro); # 10
representa LF (alimentación de línea).

Dos personajes de control más interesantes incluyen:

▪ # 0 - personaje NULL
▪ # 9 - TAB (horizontal)
Nota: así es cómo traducir una clave virtual al código ASCII.

Cómo borrar los gráficos en un control de


TImage
• by Zarko Gajic
• Un breve bloque de código Delphi salva el día

• Los programadores de Delphi usan el control de TImage para mostrar una


imagen, archivos que terminan en extensiones que incluyen ICO, BMP,
WMF, WMF, GIF y JPG. La propiedad Imagen especifica la imagen que
aparece en el control de TImage. Delphi admite varios métodos diferentes
para asignar una imagen para el componente TImage: un método
de TPicture LoadFromFile lee gráficos del disco o el método Assign obtiene
la imagen del portapapeles, por ejemplo.
• En ausencia de un comando directo para borrar la propiedad de Imagen ,
deberá asignarle un objeto "nulo". Al hacerlo, esencialmente pone en
blanco la imagen.

• Para un control de TI llamado Foto , utilice uno de los dos métodos para
borrar el gráfico asignado:

• {code: delphi}
Photo.Picture: = nil;
{código}

• o:

• {code: delphi}
Photo.Picture.Assign (nil);
{código}

• Cualquiera de los bloques de código borrará la imagen de su control de


TImage. El primer enfoque establece un valor nulo para la propiedad
de Imagen ; el segundo enfoque asigna un cero mediante el uso de un
método.

Cómo colocar una lista de selección


desplegable en un DBGrid
• by Zarko Gajic
• A continuación, le mostramos cómo colocar una lista desplegable en un
DBGrid. Cree interfaces de usuario visualmente más atractivas para editar
campos de búsqueda dentro de un DBGrid, utilizando la propiedad PickList
de una columna DBGrid.

• Ahora, para saber qué son los campos de búsqueda y cuáles son las
opciones de mostrar un campo de búsqueda en DBGrid de Delphi , es hora
de ver cómo usar la propiedad PickList de una columna DGBrid para
permitir que un usuario elija un valor para un campo de búsqueda de un
cuadro de lista desplegable.

• Una información rápida en la propiedad Columnas DBGrid


• Un control DBGrid tiene una propiedad Columnas: una colección de objetos
TColumn que representan todas las columnas en un control de cuadrícula.
Las columnas se pueden configurar en el tiempo de diseño a través del
editor de Columnas, o programáticamente en tiempo de ejecución. Por lo
general, agregará Columnas a un DBGird cuando quiera definir cómo
aparece una columna, cómo se muestran los datos en la columna y para
acceder a las propiedades, eventos y métodos de TDBGridColumns en
tiempo de ejecución. Una cuadrícula personalizada le permite configurar
varias columnas para presentar diferentes vistas del mismo conjunto de
datos (diferentes órdenes de columna, diferentes opciones de campo y
diferentes colores de columna y fuentes, por ejemplo).

• Ahora, cada columna en una grilla está "vinculada" a un campo de un


conjunto de datos que se muestra en la grilla. Además, cada columna tiene
una propiedad PickList. La propiedad PickList enumera los valores que el
usuario puede seleccionar para el valor del campo vinculado de la columna.

• Llenar el PickList
• Lo que aprenderá aquí es cómo llenar esa lista de cadenas con valores de
otro conjunto de datos en tiempo de ejecución.
Recuerde, estamos editando la tabla Artículos, y que un campo Asunto solo
puede aceptar valores de la tabla Temas: ¡situación ideal para la Lista de
Selección!

• A continuación, le mostramos cómo configurar la propiedad PickList.

• Primero, agregamos una llamada al procedimiento SetupGridPickList en el


controlador de eventos OnCreate del formulario.

• procedure TForm1.FormCreate (Sender: TObject); comenzar SetupGridPickList


('Subject', 'SELECT Name FROM Subjects'); fin ;

• La forma más fácil de crear el procedimiento SetupGridPickList es ir a la


parte privada de la declaración del formulario, agregar la declaración allí y
presionar la combinación de teclas CTRL + SHIF + C: la finalización del
código de Delphi hará el resto:

• ... tipo TForm1 = clase (TForm) ... procedimiento privado SetupGridPickList


( const FieldName: string ; const sql: string ); público ...

• Nota: el procedimiento SetupGridPickList toma dos parámetros. El primer


parámetro, FieldName, es el nombre del campo que queremos que actúe
como un campo de búsqueda; el segundo parámetro, sql, es la expresión
SQL que usamos para rellenar PickList con posibles valores; en general, la
expresión SQL debe devolver un conjunto de datos con un solo campo.

• Así es como se ve SetupGridPickList:

• procedure TForm1.SetupGridPickList ( const FieldName, sql: string ); var slPickList:


TStringList; Consulta: TADOQuery; i: entero; comenzar slPickList: =
TStringList.Create; Query: = TADOQuery.Create (self); intente Query.Connection: =
ADOConnection1; Query.SQL.Text: = sql; Query.Open; // Rellene la lista de
cadenas mientras no esté Query.EOF doy comenzar slPickList.Add (Query.Fields [0]
.AsString); Query.Next; fin ; // while // coloca la lista en la columna correcta para i:
= 0 a DBGrid1.Columns.Count-1 do si DBGrid1.Columns [i] .FieldName =
FieldName luego comienza DBGrid1.Columns [i] .PickList: = slPickList ;
Descanso; fin ; finalmente slPickList.Free; Query.Free; fin ; fin ; (* SetupGridPickList
*)

• Eso es. Ahora, cuando hace clic en la columna Asunto (para ingresar al
modo de edición).

• Nota 1: de forma predeterminada, la lista desplegable muestra 7 valores.


Puede cambiar la longitud de esta lista estableciendo la propiedad
DropDownRows.

• Nota 2: nada le impide rellenar PickList de una lista de valores que no


proviene de una tabla de base de datos. Si, por ejemplo, tiene un campo
que solo acepta nombres de días de la semana ('Lunes', ..., 'Domingos'),
puede crear una lista de selección "codificada".

• "Uh, necesito hacer clic en PickList 4 veces ..."

• Tenga en cuenta que cuando desee editar el campo que muestra una lista
desplegable, deberá hacer clic en la celda 4 veces para seleccionar un
valor de una lista. El siguiente fragmento de código, agregado al controlador
de eventos OnCellClick de DBGrid, imita un golpe en la tecla F2 seguido de
Alt + Flecha descendente.

• procedimiento TForm1.DBGrid1CellClick (Columna: TColumn); begin // Hacer que


la lista desplegable aparezca más rápida si Column.PickList.Count>
0 luego comienza keybd_event (VK_F2,0,0,0); keybd_event (VK_F2,0,
KEYEVENTF_KEYUP, 0); keybd_event (VK_MENU, 0,0,0); keybd_event (VK_DOWN,
0,0,0); keybd_event (VK_DOWN, 0, KEYEVENTF_KEYUP, 0); keybd_event (VK_MENU,
0, KEYEVENTF_KEYUP, 0); fin ; fin ;

Cómo agregar casillas de verificación y


botones de radio a un TTreeView
• by Zarko Gajic

El componente TTreeView Delphi (ubicado en la pestaña de la paleta del


componente "Win32") representa una ventana que muestra una lista jerárquica de
elementos, como los títulos de un documento, las entradas de un índice o los
archivos y directorios de un disco.
Nodo de árbol con casilla de verificación o botón de radio?
El TTreeview de Delphi no admite casillas de verificación de forma nativa, pero sí
el control WC_TREEVIEW subyacente. Puede agregar casillas de verificación a
la vista de árbol anulando el procedimiento CreateParams de TTreeView,
especificando el estilo de TVS_CHECKBOXES para el control (vea MSDN para
más detalles).

El resultado es que todos los nodos en la vista de árbol tendrán casillas de


verificación asociadas. Además, la propiedad StateImages ya no se puede usar
porque WC_TREEVIEW usa esta lista de imágenes internamente para
implementar casillas de verificación. Si desea alternar las casillas de verificación,
tendrá que hacer eso usando SendMessage o

TreeView_SetItem / TreeView_GetItem macros de CommCtrl.pas. El


WC_TREEVIEW solo admite casillas de verificación, no botones de opción.

El enfoque que debe descubrir en este artículo es mucho más flexible: puede tener
casillas de verificación y botones de radio mezclados con otros nodos de la forma
que desee sin cambiar el TTreeview o crear una nueva clase a partir de él para
que esto funcione. Además, usted mismo decide qué imágenes usar para las
casillas de verificación / botones de radio simplemente agregando las imágenes
adecuadas a la lista de imágenes de StateImages.

TreeNode con casilla de verificación o botón de radio


Al contrario de lo que puedas creer, esto es bastante simple de lograr en Delphi.

Estos son los pasos para hacer que funcione:

▪ Configure una lista de imágenes (componente TImageList en la pestaña de la paleta del


componente "Win32") para la propiedad TTreeview.StateImages que contiene las
imágenes para los estados marcados y sin marcar para las casillas de verificación y / o
botones de opción.
▪ Llame al procedimiento ToggleTreeViewCheckBoxes (consulte a continuación) en los
eventos OnClick y OnKeyDown de treeview. El procedimiento
ToggleTreeViewCheckBoxes altera el StateIndex del nodo seleccionado para reflejar el
estado actual marcado / no verificado.
Para que su vista de árbol sea aún más profesional, debe verificar dónde se hace
clic en un nodo antes de alternar las imágenes de estado: al solo alternar el nodo
cuando se hace clic en la imagen real, los usuarios pueden seleccionar el nodo sin
cambiar su estado.

Además, si no desea que sus usuarios expandan / colapsen la vista de árbol,


llame al procedimiento FullExpand en el evento OnShow de formularios y
establezca AllowCollapse en false en el evento OnCollapsing de la vista de árbol.

Aquí está la implementación del procedimiento ToggleTreeViewCheckBoxes:


procedure ToggleTreeViewCheckBoxes (Node: TTreeNode; cUnChecked, cChecked,
cRadioUnchecked, cRadioChecked: integer); var tmp: TTreeNode; comience si Asignado
(Nodo) luego comience si Node.StateIndex = cUnChecked then Node.StateIndex: =
cChecked else si Node.StateIndex = cChecked then Node.StateIndex: = cUnChecked else
si Node.StateIndex = cRadioUnChecked then begin tmp: = Node.Parent ; si no Asignado
(tmp) entonces tmp: = TTreeView (Node.TreeView) .Items.getFirstNode else tmp: =
tmp.getFirstChild; mientras Assigned
(tmp) comienza si (tmp.StateIndex en [cRadioUnChecked,
cRadioChecked]) then tmp.StateIndex: = cRadioUnChecked; tmp: =
tmp.getNextSibling; fin ; Node.StateIndex: = cRadioChecked; fin ; // si StateIndex =
cRadioUnChecked end ; // si Assigned (Node) end ; (* ToggleTreeViewCheckBoxes *)

Como puede ver en el código anterior, el procedimiento comienza buscando los


nodos de las casillas de verificación y simplemente activándolos o
desactivándolos. Luego, si el nodo es un botón de radio no seleccionado, el
procedimiento se mueve al primer nodo en el nivel actual, establece todos los
nodos en ese nivel en cRadioUnchecked (si son nodos cRadioUnChecked o
cRadioChecked) y finalmente alterna Node a cRadioChecked.

Observe cómo se ignoran los botones de opción ya controlados. Obviamente, esto


se debe a que un botón de radio ya verificado se alternará para desmarcarse,
dejando los nodos en un estado indefinido. Difícilmente lo que querrías la mayor
parte del tiempo.

Aquí se explica cómo hacer que el código sea aún más profesional: en el evento
OnClick de TreeView, escriba el siguiente código para alternar las casillas de
verificación solo si se hizo clic en el estado (las constantes cFlatUnCheck,
cFlatChecked, etc. se definen en otros lugares como índices en la lista de
imágenes de StateImages) :

procedure TForm1.TreeView1Click (Sender: TObject); var P:


TPoint; comenzar GetCursorPos (P); P: = TreeView1.ScreenToClient
(P); if (htOnStateIcon en TreeView1.GetHitTestInfoAt (PX,
PY)) luego ToggleTreeViewCheckBoxes (TreeView1.Selected, cFlatUnCheck, cFlatChecked,
cFlatRadioUnCheck, cFlatRadioChecked); fin ; (* TreeView1Click *)

El código obtiene la posición actual del mouse, se convierte en coordenadas de


vista en árbol y comprueba si se hizo clic en StateIcon llamando a la función
GetHitTestInfoAt. Si lo fue, se llama al procedimiento de alternar.

Principalmente, esperaría que la barra espaciadora alternase las casillas de


verificación o los botones de opción, así que aquí se explica cómo escribir el
evento TreeView OnKeyDown usando ese estándar:

procedure TForm1.TreeView1KeyDown (Sender: TObject; var Clave: Word; Shift:


TShiftState); begin if (Key = VK_SPACE) y Assigned
(TreeView1.Selected) luego ToggleTreeViewCheckBoxes (TreeView1.Selected,
cFlatUnCheck, cFlatChecked, cFlatRadioUnCheck, cFlatRadioChecked); fin; (*
TreeView1KeyDown *)

Finalmente, así es como podrían verse los eventos OnShow y TreeView


OnChanging del formulario si desea evitar el colapso de los nodos de treeview:

procedure TForm1.FormCreate (Sender: TObject); comenzar TreeView1.FullExpand; fin ; (*


FormCreate *) procedure TForm1.TreeView1Collapsing (Sender: TObject; Node:
TTreeNode; var AllowCollapse: Boolean); begin AllowCollapse: = falso; fin ; (*
TreeView1Collapsing *)

Finalmente, para verificar si un nodo está marcado, simplemente haga la siguiente


comparación (en el controlador de eventos OnClick de Button, por ejemplo):

procedure TForm1.Button1Click (Sender: TObject); var BoolResult: boolean; tn:


TTreeNode; comience si Asignado (TreeView1.Selected) luego comience tn: =
TreeView1.Selected; BoolResult: = tn.StateIndex en [cFlatChecked, cFlatRadioChecked];
Memo1.Text: = tn.Text + # 13 # 10 + 'Seleccionado:' + BoolToStr (BoolResult,
True); fin ; fin ; (* Button1Click *)

Aunque este tipo de codificación no se puede considerar de misión crítica, puede


dar a sus aplicaciones un aspecto más profesional y más suave. Además, al usar
juiciosamente las casillas de verificación y los botones de radio, pueden hacer que
su aplicación sea más fácil de usar. ¡Seguro que se verán bien!

Esta imagen a continuación fue tomada de una aplicación de prueba utilizando el


código descrito en este artículo. Como puede ver, puede mezclar libremente
nodos con casillas de verificación o botones de radio con los que no tienen
ninguno, aunque no debe mezclar nodos "vacíos" con nodos de " casilla " (mire los
botones de opción de la imagen) ya que hace que sea muy difícil ver qué nodos
están relacionados.

Administrar archivos Ascii (texto) desde


código
• by Zarko Gajic
• En pocas palabras, los archivos de texto contienen
caracteres ASCII legibles. Podemos pensar en trabajar con un archivo de
texto en Delphi como análogo a reproducir o grabar información en una
cinta de video.

Aunque es posible realizar cambios en un archivo de texto, saltar cuando se


procesa la información o agregar algunos datos al archivo que no sean al
final, es aconsejable utilizar un archivo de texto solo cuando sabemos que
estamos trabajando con texto normal y ninguna de esas operaciones es
necesaria.

• Se considera que los archivos de texto representan una secuencia de


caracteres formateados en líneas, donde cada línea termina con un
marcador de final de línea ( una combinación CR / LF ).

• El archivo de texto y el método de asignación


• Para comenzar a trabajar con archivos de texto, debe vincular un archivo en
un disco a una variable de archivo en su código: declare una variable de
tipo TextFile y use el procedimiento AssignFile para asociar un archivo en
un disco con una variable de archivo.

• > var SomeTxtFile: TextFile; comenzar AssignFile (SomeTxtFile, FileName)

• Lectura de información de un archivo de texto


• Si queremos volver a leer el contenido de un archivo en una lista de
cadenas, solo una línea de código hará el trabajo.

• > Memo1.Lines.LoadFromFile ('c: \ autoexec.bat')

• Para leer información de un archivo línea por línea, debemos abrir el


archivo para ingresar utilizando el procedimiento Restablecer . Una vez que
se restablece un archivo, podemos usar ReadLn para leer información de
un archivo (lee una línea de texto de un archivo y luego pasa a la siguiente):

• > var SomeTxtFile: TextFile; buffer: cadena ; comenzar AssignFile (SomeTxtFile, 'c: \
autoexec.bat'); Restablecer (SomeTxtFile); ReadLn (SomeTxtFile,
buffer); Memo1.Lines.Add (buffer); CloseFile (SomeTxtFile); fin ;

• Después de agregar una línea de texto de un archivo a un componente


memo, se debe cerrar SomeTxtFile.

• Esto se hace con la palabra clave Cerrar .

• También podemos usar el procedimiento de lectura para leer información


de un archivo. Read funciona igual que ReadLn, excepto que no mueve el
puntero a la siguiente línea.

• > var SomeTxtFile: TextFile; buf1, buf2: cadena [5]; comenzar AssignFile
(SomeTxtFile, 'c: \ autoexec.bat'); Restablecer (SomeTxtFile); ReadLn (SomeTxtFile,
buf1, buf2); ShowMessage (buf1 + '' + buf2); CloseFile (SomeTxtFile); fin ;

• EOF - Fin del archivo


• Use la función EOF para asegurarse de que no está tratando de leer más
allá del final del archivo. Digamos que queremos mostrar el contenido del
archivo en cuadros de mensaje, una línea a la vez hasta que lleguemos al
final de un archivo:

• > var SomeTxtFile: TextFile; buffer: cadena ; comenzar AssignFile (SomeTxtFile, 'c: \
autoexec.bat'); Restablecer (SomeTxtFile); mientras que no EOF
(SomeTxtFile) comienzan ReadLn (SomeTxtFile, buffer); ShowMessage
(buffer); fin ; CloseFile (SomeTxtFile); fin ;

• Nota: es mejor utilizar el ciclo While que el ciclo Until para tener en cuenta
la posibilidad (poco probable) de que el archivo exista pero no contenga
ningún dato.

• Escribir texto en un archivo


• El WriteLn es probablemente la forma más común de enviar piezas de
información individuales a un archivo.

• El siguiente código leerá un texto de un componente Memo1 (línea por


línea) y lo enviará a un archivo de texto recién creado.

• > var SomeTxtFile: TextFile; j: entero; comenzar AssignFile (SomeTxtFile, 'c: \


MyTextFile.txt'); Reescribir (SomeTxtFile); para j: = 0 a (-1 +
Memo1.Lines.Count) do WriteLn (SomeTxtFile, Memo1.Lines [j]); CloseFile
(SomeTxtFile); fin ;

• Dependiendo del estado del archivo proporcionado al procedimiento


Rewrite, crea un nuevo archivo (abre el archivo para la salida) con el
nombre asignado a SomeTextFile. Si ya existe un archivo con el mismo
nombre, se elimina y se crea un nuevo archivo vacío en su lugar. Si
SomeTextFile ya está abierto, primero se cierra y luego se vuelve a crear.
La posición actual del archivo está configurada al principio del archivo
vacío.

• Nota: Memo1.Lines.SaveToFile ('c: \ MyTextFile.txt') hará lo mismo.

• Algunas veces solo necesitaremos agregar algunos datos de texto al final


de un archivo existente. Si este es el caso, llamaremos a Append para
asegurarnos de que se abre un archivo con acceso de solo escritura con el
puntero de archivo ubicado al final del archivo. Algo como:

• > var SomeTxtFile: TextFile; comenzar AssignFile (SomeTxtFile, 'c: \


MyTextFile.txt'); Adjuntar (SomeTxtFile); WriteLn (SomeTxtFile, 'Nueva línea en
mi archivo de texto '); CloseFile (SomeTxtFile); fin ;

• Tenga cuidado con las excepciones


• En general, siempre debe usar el manejo de excepciones cuando trabaje
con archivos. I / O está lleno de sorpresas. Utilice siempre CloseFile en un
bloque finally para evitar la posibilidad de corromper la FAT de un usuario.
Todos los ejemplos anteriores deben reescribirse de la siguiente manera:

• > var SomeTxtFile: TextFile; buffer: cadena; comenzar AssignFile (SomeTxtFile, 'c: \
MyTextFile.txt'); intente restablecer (SomeTxtFile); ReadLn (SomeTxtFile,
buffer); finalmente CloseFile (SomeTxtFile); fin ; fin ;

Crear una base de datos usando el


"Archivo de" archivos tipados de Delphi
• by Zarko Gajic
• Comprender los archivos tipados

• Simplemente ponga un archivo es una secuencia binaria de algún tipo.


En Delphi , hay tres clases de archivos : tipeado, texto y sin tipo . Los
archivos tipados son archivos que contienen datos de un tipo particular,
como Doble, Entero o tipo de registro personalizado previamente definido.
Los archivos de texto contienen caracteres ASCII legibles. Los archivos sin
tipo se utilizan cuando queremos imponer la menor estructura posible en un
archivo.

• Archivos mecanografiados
• Mientras que los archivos de texto consisten en líneas terminadas con una
combinación CR / LF ( # 13 # 10 ), los archivos tipeados consisten en
datos tomados de un tipo particular de estructura de datos .

• Por ejemplo, la siguiente declaración crea un tipo de registro llamado


TMember y una matriz de variables de registro de TMember.

• > escriba TMember


= registro Nombre: cadena [50]; eMail: cadena [30]; Publicaciones:
LongInt; fin ; var Miembros: array [1..50] de TMember;

• Antes de que podamos escribir la información en el disco, tenemos que


declarar una variable de un tipo de archivo. La siguiente línea de código
declara una variable de archivo F.

• > var F: archivo de TMember;

• Nota: Para crear un archivo tipado en Delphi, usamos la siguiente sintaxis :

• var SomeTypedFile: archivo de SomeType

• El tipo de base (SomeType) para un archivo puede ser de tipo escalar


(como Double), un tipo de matriz o un tipo de registro. No debería ser
cadena larga, matriz dinámica, clase, objeto o puntero.
• Para comenzar a trabajar con archivos de Delphi, tenemos que vincular un
archivo en un disco a una variable de archivo en nuestro programa. Para
crear este enlace debemos usar el procedimiento AssignFile para asociar
un archivo en un disco con una variable de archivo.

• > AssignFile (F, 'Members.dat')

• Una vez establecida la asociación con un archivo externo, la variable de


archivo F debe estar 'abierta' para prepararla para lectura y / o escritura.
Llamamos al procedimiento Restablecer para abrir un archivo existente o
Reescribir para crear un nuevo archivo. Cuando un programa completa el
procesamiento de un archivo, el archivo debe cerrarse usando el
procedimiento CloseFile.

• Después de cerrar un archivo, se actualiza su archivo externo asociado. La


variable de archivo puede asociarse con otro archivo externo.

• En general, siempre debemos usar el manejo de excepciones ; muchos


errores pueden surgir al trabajar con archivos. Por ejemplo: si llamamos a
CloseFile para un archivo que ya está cerrado, Delphi informa un error de E
/ S. Por otro lado, si tratamos de cerrar un archivo pero aún no hemos
llamado a AssignFile, los resultados son impredecibles.

• Escribir en un archivo
• Supongamos que hemos llenado un conjunto de miembros de Delphi con
sus nombres, correos electrónicos y número de publicaciones, y queremos
almacenar esta información en un archivo en el disco. La siguiente pieza de
código hará el trabajo:

• > var F: archivo de TMember; i: entero; comenzar AssignFile (F,


'members.dat'); Reescribir (F); intente con j: = 1 a 50 do Write (F, Members
[j]); finalmente CloseFile (F); fin ; fin ;

• Leer de un archivo
• Para recuperar toda la información del archivo 'members.dat', usaríamos el
siguiente código :

• > var Miembro: TMember F: archivo de TMember; comenzar AssignFile (F,


'members.dat'); Restablecer (F); intente mientras no Eof (F) comiencen a leer (F,
miembro); {DoSomethingWithMember;} end ; finalmente CloseFile (F); fin ; fin ;

• Nota: Eof es la función de comprobación EndOfFile. Utilizamos esta función


para asegurarnos de que no estamos tratando de leer más allá del final del
archivo (más allá del último registro almacenado).
• Buscando y posicionando
• Normalmente, se accede a los archivos secuencialmente. Cuando se lee un
archivo usando el procedimiento estándar Leído o escrito usando el
procedimiento estándar Escribir, la posición actual del archivo se mueve al
siguiente componente de archivo ordenado numéricamente (próximo
registro). También se puede acceder aleatoriamente a los archivos tipeados
a través del procedimiento estándar Buscar, que mueve la posición actual
del archivo a un componente específico. Las
funciones FilePos y FileSize se pueden usar para determinar la posición
actual del archivo y el tamaño actual del archivo.

• > {volver al principio - el primer registro} Buscar (F, 0); {ir al registro 5 °} Buscar (F,
5); {Saltar al final - "después" del último registro} Buscar (F, FileSize (F));

• Cambiar y actualizar
• Acaba de aprender a escribir y leer todo el conjunto de miembros, pero
¿qué sucede si lo único que desea hacer es buscar al 10º miembro y
cambiar el correo electrónico? El siguiente procedimiento hace
exactamente eso:

• > procedimiento ChangeEMail ( const RecN:


integer; const NewEMail: string ); var DummyMember: TMember; begin {assign,
open, exception handling block} Buscar (F, RecN); Lee (F,
DummyMember); DummyMember.Email: = NewEMail; {leer mueve al siguiente
registro, tenemos que volver al registro original, luego escribir} Buscar (F,
RecN); Escribir (F, DummyMember); {archivo cerrado} final ;

• Completando la tarea
• Eso es todo, ahora tienes todo lo que necesitas para llevar a cabo tu tarea.
Puede escribir la información de los miembros en el disco, puede leerla e
incluso puede cambiar algunos de los datos (correo electrónico, por
ejemplo) en el "medio" del archivo.

• Lo importante es que este archivo no es un archivo ASCII , así es como se


ve en el Bloc de notas (solo un registro):

• > .Delphi Guide g Ò5 · ¿ì. 5.. B V.Lƒ, "¨.delphi@aboutguide.comÏ .. ç.ç.ï ..


Almacenar una cadena (o un objeto) junto
con una cadena en un ListBox o
ComboBox
Comprender el método TStrings.AddObject

TListBox y TComboBox de Delphi muestran una lista de elementos: cadenas en


una lista "seleccionable". TListBox muestra una lista desplazable, TComboBox
muestra una lista desplegable.

Una propiedad común de todos los controles anteriores es la propiedad Artículos .


Items define una lista de cadenas que aparecerán en el control para el usuario. En
el momento del diseño, cuando hace doble clic en la propiedad Elementos, el
"Editor de listas de cadenas" le permite especificar elementos de cadena.

La propiedad Items es en realidad un descendiente del tipo TStrings.

Dos cadenas por artículo en un ListBox?

Hay situaciones en las que desea mostrar una lista de cadenas para el usuario, por
ejemplo, en el control de cuadro de lista, pero también tiene una forma
de almacenar una cadena adicional más a lo largo de la que se muestra al
usuario .
Además, es posible que desee almacenar / adjuntar más que solo una cadena
"simple" a la cadena, es posible que desee adjuntar un objeto al elemento
(cadena) .

ListBox.Items - TStrings "conoce" Objetos!

Dele al objeto TStrings una apariencia más en el sistema de Ayuda. Está la


propiedad Objects que representa un conjunto de objetos que están asociados
con cada una de las cadenas en la propiedad Strings, donde la propiedad Strings
hace referencia a las cadenas reales en la lista.
Si desea asignar una segunda cadena (o un objeto) a cada cadena en el cuadro
de lista, debe rellenar la propiedad Elementos en tiempo de ejecución.

Si bien puede usar el método ListBox.Items.Add para agregar cadenas a la lista,


para asociar un objeto a cada cadena, deberá usar otro enfoque.
El método ListBox.Items.AddObject acepta dos parámetros . El primer parámetro,
"Artículo" es el texto del artículo. El segundo parámetro, "AObject" es el objeto
asociado con el elemento.

Tenga en cuenta que el cuadro de lista expone el método AddItem que hace lo
mismo que Items.AddObject.

Dos cadenas para una cadena, por favor ...

Como Items.AddObject y AddItem aceptan una variable de tipo TObject para su


segundo parámetro, una línea como: > // ¡compila el
error! ListBox1.Items.AddObject ('zarko', 'gajic'); dará como resultado un error de
compilación: E2010 Tipos incompatibles: 'TObject' y 'string' .
No puede simplemente proporcionar una cadena para el objeto, ya que en Delphi
para Win32 los valores de cadena no son objetos.

Para asignar una segunda cadena al elemento del cuadro de lista, debe
"transformar" una variable de cadena en un objeto; necesita un objeto TString
personalizado.

Un entero para una cadena, por favor ...

Si el segundo valor que necesita almacenar junto con el elemento de cadena es un


valor entero, en realidad no necesita una clase TInteger personalizada. >
ListBox1.AddItem ('Zarko Gajic', TObject (1973)); La línea superior almacena el
número entero "1973" a lo largo de la cadena "Zarko Gajic" añadida.
Ahora esto es complicado :)
Un elenco de tipo directo de un entero a un objeto se hace arriba. El parámetro
"AObject" es en realidad el puntero de 4 bytes (dirección) del objeto agregado.
Dado que en Win32 un entero ocupa 4 bytes, es posible un lanzamiento tan difícil.

Para recuperar el entero asociado a la cadena, debe volver a convertir el "objeto"


en el valor entero:

> // año == 1973 año: = Entero (ListBox1.Items.Objects [ListBox1.Items.IndexOf


('Zarko Gajic')]);

Un control Delphi para una cadena, por favor ...

¿Por qué parar aquí? Asignar cadenas y enteros a una cadena en un cuadro de lista
es, como acaba de experimentar, un pedazo de pastel.
Como los controles Delphi son en realidad objetos, puede adjuntar un control a
cada cadena mostrada en el cuadro de lista.
El siguiente código agrega los títulos de ListBox1 (cuadro de lista) de todos los
controles de TButton en un formulario (coloque esto en el controlador de eventos
OnCreate del formulario) junto con la referencia a cada botón.

> var idx: entero; begin for idx: = 0 a -1 +


ComponentCount do begin if Componentes
[idx] es TButton luego ListBox1.AddObject (TButton (Componentes [idx]). Leyenda,
Componentes [idx]); fin ; fin ; Para hacer clic * en el programa * el botón "segundo",
puede usar la siguiente instrucción: > TButton (ListBox1.Items.Objects [1]). Haga clic;

¡Quiero asignar mis objetos personalizados al elemento String!

En una situación más genérica, debería agregar instancias (objetos) de sus propias
clases personalizadas: > escriba TStudent = class private fName: string; fYear:
entero; propiedad pública Nombre: string read fName; propiedad Año:
entero leído fYear; constructor Create (nombre de const : cadena ; const year:
integer); fin ; ........ constructor TStudent.Create (nombre
de const : cadena ; const year: integer); begin fName: = nombre; fYear: =
año; fin ; -------- begin // agrega dos cadenas / objetos -> students a la
lista ListBox1.AddItem ('John', TStudent.Create ('John', 1970)); ListBox1.AddItem
('Jack', TStudent.Create ('Jack', 1982)); // tomar el primer alumno - John student: =
ListBox1.Items.Objects [0] como TStudent; // muestra el año de John ShowMessage
(IntToStr (student.Year)); fin ;

¡Lo que creas DEBES GRATIS!

Esto es lo que la Ayuda tiene que decir sobre los objetos en los descendientes de
TStrings: el objeto TStrings no posee los objetos que agrega de esta manera. Los
objetos añadidos al objeto TStrings aún existen aunque se destruya la instancia de
TStrings. Deben ser explícitamente destruidos por la aplicación.
Cuando agrega objetos a cadenas - objetos que crea - debe asegurarse de liberar
la memoria ocupada, o tendrá una pérdida de memoria

Un procedimiento personalizado genérico FreeObjects acepta una variable de tipo


TStrings como su único parámetro. FreeObjects liberará cualquier objeto asociado
con un elemento en la lista de cadenas. En el ejemplo anterior, los "estudiantes"
(clase TStudent) se adjuntan a una cadena en un cuadro de lista, cuando la
aplicación está a punto de cerrarse (evento OnDestroy de forma principal, para
ejemplo), necesitas liberar la memoria ocupada:

> FreeObjects (ListBox1.Items); Nota: SÓLO llama a este procedimiento cuando los
objetos asignados a los elementos de cadena fueron creados por usted.
Tamaño del ancho desplegable del
ComboBox: sin corte para las ubicaciones
del borde derecho
• by Zarko Gajic
• Asegura que la lista desplegable sea visible cuando se muestra la lista
desplegable

• El componente TComboBox combina un cuadro de edición con una lista de


"selección" desplazable. Los usuarios pueden seleccionar un elemento de
la lista o escribir directamente en el cuadro de edición .

• La lista desplegable
• Cuando un cuadro combinado está en estado desplegable, Windows dibuja un tipo
de cuadro de control para mostrar los elementos del cuadro combinado para su
selección.

• La propiedad DropDownCount especifica la cantidad máxima de


elementos que se muestran en la lista desplegable.

• El ancho de la lista desplegable sería, por defecto, igual al ancho del


cuadro combinado.

• Cuando la longitud (de una cadena) de elementos excede el ancho del


cuadro desplegable, los elementos se muestran como punto de corte.

• TComboBox no proporciona una forma de establecer el ancho de su lista


desplegable :(

• Reparar el ancho de la lista desplegable de ComboBox


• Podemos establecer el ancho de la lista desplegable enviando un mensaje especial
de Windows al cuadro combinado. El mensaje es CB_SETDROPPEDWIDTH y envía
el ancho mínimo permitido, en píxeles, del cuadro de lista de un cuadro
combinado.

• Para núcleo duro el tamaño de la lista desplegable para, digamos, 200


píxeles, podría hacer: >

• >> SendMessage (theComboBox.Handle, CB_SETDROPPEDWIDTH, 200, 0); Esto solo


está bien si está seguro de que todos sus artículos de TheComboBox no superan
los 200 px (cuando se dibujan).

• Para garantizar que siempre tengamos la lista desplegable lo


suficientemente ancha, podemos calcular el ancho requerido.
• Aquí hay una función para obtener el ancho requerido de la lista
desplegable y configurarlo: >

• >> procedimiento ComboBox_AutoWidth ( const theComboBox:


TCombobox); const HORIZONTAL_PADDING = 4; var itemsFullWidth: integer; idx:
entero; itemWidth: integer; begin itemsFullWidth: = 0; // obtener el máximo
necesario con los elementos en el estado desplegable para idx: = 0 a -1 +
theComboBox.Items.Count do begin itemWidth: = theComboBox.Canvas.TextWidth
(theComboBox.Items [idx]); Inc (itemWidth, 2 * HORIZONTAL_PADDING); if
(itemWidth> itemsFullWidth) then itemsFullWidth: = itemWidth; fin ; // establece el
ancho de desplegable si es necesario if (itemsFullWidth> theComboBox.Width)
luego comienza // comprueba si habría una barra de
desplazamiento si theComboBox.DropDownCount luego itemsFullWidth: =
itemsFullWidth + GetSystemMetrics (SM_CXVSCROLL) ; SendMessage
(theComboBox.Handle, CB_SETDROPPEDWIDTH, itemsFullWidth, 0); fin ; fin ; El
ancho de la cadena más larga se utiliza para el ancho de la lista desplegable.

• Cuándo llamar a ComboBox_AutoWidth?


Si completa previamente la lista de elementos (en tiempo de diseño o al
crear el formulario), puede llamar al procedimiento ComboBox_AutoWidth
dentro del controlador de evento OnCreate del formulario.

• Si cambia dinámicamente la lista de elementos del cuadro combinado,


puede llamar al procedimiento ComboBox_AutoWidth dentro del controlador
de eventos OnDropDown : se produce cuando el usuario abre la lista
desplegable.

• Una prueba
Para una prueba, tengo 3 cuadros combinados en un formulario. Todos
tienen elementos con su texto más ancho que el ancho real del cuadro
combinado.

• El tercer cuadro combinado se coloca cerca del borde derecho del borde
del formulario.

• La propiedad Items, para este ejemplo, está precargada: llamo a mi


ComboBox_AutoWidth en el controlador de eventos OnCreate para el
formulario: >

• >> // Procedimiento OnCreate del formulario TForm.FormCreate (Sender:


TObject); Comience con ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth
(ComboBox3); fin ;

• ¡No he llamado a ComboBox_AutoWidth para Combobox1 para ver la


diferencia!
• Tenga en cuenta que, cuando se ejecuta, la lista desplegable de
Combobox2 será más amplia que Combobox2.

• :( Toda la lista desplegable está cortada para la "Ubicación del borde


más cercano al derecho"
• Para Combobox3, el que se encuentra cerca del borde derecho, la lista desplegable
se corta.

• El envío de CB_SETDROPPEDWIDTH siempre extenderá el cuadro de la


lista desplegable a la derecha. Cuando su cuadro combinado esté cerca del
borde derecho, al extender el cuadro de lista más a la derecha se cortará la
visualización del cuadro de lista.

• Necesitamos de alguna manera extender el cuadro de lista a la izquierda


cuando este es el caso, no a la derecha.

• El CB_SETDROPPEDWIDTH no tiene forma de especificar en qué


dirección (izquierda o derecha) extender el cuadro de lista.

• Solución: WM_CTLCOLORLISTBOX
• Justo cuando se va a mostrar la lista desplegable, Windows envía el mensaje
WM_CTLCOLORLISTBOX a la ventana principal de un cuadro de lista: a nuestro
cuadro combinado.

• Ser capaz de manejar el WM_CTLCOLORLISTBOX para mi combobox


cercano a la derecha resolvería el problema.

• All Might WindowProc


Cada control de VCL expone la propiedad WindowProc, el procedimiento
que responde a los mensajes enviados al control. Podemos usar la
propiedad WindowProc para reemplazar temporalmente o subclasificar el
procedimiento de ventana del control.

• Aquí está nuestro WindowProc modificado para Combobox3 (el que está
cerca del borde derecho): >

• >> // procedimiento modificado de WindowProc de


ComboBox3 TForm.ComboBox3WindowProc ( var Message: TMessage); var cr, lbr:
TRect; comience // dibujando el cuadro de lista con elementos del cuadro
combinado si Message.Msg = WM_CTLCOLORLISTBOX
luego comienza GetWindowRect (ComboBox3.Handle, cr); // list box
rectangle GetWindowRect (Message.LParam, lbr); // moverlo a la izquierda para que
coincida con el borde derecho si cr.Right <> lbr.Right y luego MoveWindow
(Message.LParam, lbr.Left- (lbr.Right-clbr.Right), lbr.Top, lbr.Right-lbr. Izquierda,
lbr.Bottom-lbr.Top, True); end else ComboBox3WindowProcORIGINAL
(Mensaje); fin ; Si el mensaje que recibe nuestro cuadro combinado es
WM_CTLCOLORLISTBOX obtenemos el rectángulo de su ventana, también
obtenemos el rectángulo del cuadro de lista que se mostrará (GetWindowRect). Si
parece que el cuadro de lista aparecerá más a la derecha, lo movemos hacia la
izquierda para que el cuadro combinado y el borde derecho del cuadro de lista
sean los mismos. Tan fácil como eso :)

• Si el mensaje no es WM_CTLCOLORLISTBOX simplemente llamamos al


procedimiento de manejo de mensaje original para el cuadro combinado
(ComboBox3WindowProcORIGINAL).

• Finalmente, todo esto puede funcionar si lo hemos configurado


correctamente (en el controlador de eventos OnCreate para el formulario): >

• >> // Procedimiento OnCreate del formulario TForm.FormCreate (Sender:


TObject); Comience con ComboBox_AutoWidth (ComboBox2); ComboBox_AutoWidth
(ComboBox3); // adjuntar WindowProc modificado / personalizado para
ComboBox3 ComboBox3WindowProcORIGINAL: =
ComboBox3.WindowProc; ComboBox3.WindowProc: =
ComboBox3WindowProc; fin ; Donde en la declaración del formulario tenemos
(completo): >>> tipo TForm = class (TForm) ComboBox1: TComboBox; ComboBox2:
TComboBox; ComboBox3: TComboBox; procedimiento FormCreate (Sender:
TObject); private ComboBox3WindowProcORIGINAL:
TWndMethod; procedimiento ComboBox3WindowProc ( var Message:
TMessage); public {Public declarations} end ;

• Y eso es. Todo manejado :)

Almacene más datos (personalizados) en


el nodo de árbol de una vista de árbol
• by Zarko Gajic

TTreeNode.Data Y / O TTreeView.OnCreateNodeClass

El componente TTreeView Delphi muestra una lista jerárquica de


elementos: nodos de árbol . Un nodo se presenta por el texto del nodo y una
imagen opcional. Cada nodo en una vista en árbol es una instancia de una clase
TTreeNode.

Si bien puede completar la vista de árbol con elementos en el momento del


diseño, utilizando el Editor de elementos de TreeView , en la mayoría de los casos
debería completar su vista de árbol en tiempo de ejecución, dependiendo de la
aplicación.
El Editor de elementos TreeView revela que solo hay un puñado de información
que puede "adjuntar" a un nodo: texto y algunos índices de imagen (para el estado
normal, expandido, seleccionado y similar).

En esencia, el componente de vista en árbol es fácil de programar. Hay un par de


métodos para agregar nuevos nodos al árbol y establecer su jerarquía.

A continuación, le mostramos cómo agregar 10 nodos a la vista de árbol


(denominada "TreeView1"). Tenga en cuenta que la propiedad Elementos
proporciona acceso a todos los nodos en el árbol. AddChild agrega un nuevo nodo
a la vista de árbol. El primer parámetro es el nodo primario (para construir la
jerarquía) y el segundo parámetro es el texto del nodo.

> var tn: TTreeNode; cnt: entero; comenzar TreeView1.Items.Clear; para cnt: =
0 a 9 do begin tn: = TreeView1.Items.AddChild ( nil , IntToStr (cnt)); fin ; fin ;
AddChild devuelve el TTreeNode recién agregado. En el ejemplo de
código anterior, los 10 nodos se agregan como nodos raíz (no tienen nodo
principal).

En situaciones más complejas, deseará que sus nodos lleven más


información , preferiblemente para tener algunos valores especiales
(propiedades) que sean específicos del proyecto que está desarrollando.

Supongamos que desea mostrar los datos del pedido de cliente de su base de
datos. Cada cliente puede tener más pedidos y cada orden se compone de más
artículos. Esta es una relación jerárquica que se puede mostrar en una vista de
árbol:

> - Cliente_1 | - Order_1_1 | - Item_1_1_1 | - Item_1_1_2 | - Order_2 | - Item_2_1 -


Customer_2 | - Order_2_1 | - Item_2_1_1 | - Item_2_1_2
En su base de datos, habría más información para cada pedido y para cada
artículo. La vista en árbol muestra el estado actual (solo lectura) y desea ver
detalles por pedido (o incluso por artículo) para el pedido seleccionado.

Cuando el usuario selecciona el nodo "Order_1_1", desea que los detalles del
pedido (suma total, fecha, etc.) se muestren al usuario.

Puede, en ese momento, obtener los datos requeridos de la base de datos, PERO
debe conocer el identificador único (digamos un valor entero) del orden
seleccionado para obtener los datos correctos.

Necesitamos una forma de almacenar este identificador de orden junto con el


nodo, pero no podemos usar la propiedad Text. El valor personalizado que
necesitamos almacenar en cada nodo es un número entero (solo un ejemplo).
Cuando ocurre una situación de este tipo, es posible que tenga la tentación de
buscar la propiedad Tag (muchos componentes Delphi sí lo tienen), pero la
propiedad Tag no está expuesta a la clase TTreeNode.

Agregar datos personalizados a nodos de árbol: la propiedad


TreeNode.Data

La propiedad de Datos de un nodo de árbol le permite asociar sus datos


personalizados con un nodo de árbol. Los datos son un puntero y pueden señalar
objetos y registros. La visualización de datos XML (RSS Feed) en una TreeView
muestra cómo almacenar una variable de tipo de registro en la propiedad Data de
un nodo de árbol.

Muchas clases de elementos muestran la propiedad Datos: puede usarla para


almacenar cualquier objeto junto con el elemento. Un ejemplo es el TListItem de
un componente TListView. A continuación, le mostramos cómo agregar objetos a
la propiedad de Datos .

Agregar datos personalizados a nodos de árbol:


TreeView.CreateNodeClass

Si no desea utilizar la propiedad Data del TTreeNode, sino que desea que su
TreeNode se amplíe con algunas propiedades, Delphi también tiene una solución.

Digamos que quieres ser capaz de hacer

> "TreeView1.Selected.MyProperty: = 'nuevo valor'".


Aquí se explica cómo extender el TTreeNode estándar con algunas propiedades
propias:

1. Crea tu TMyTreeNode extendiendo el TTreeNode.


2. Agregue una propiedad de cadena MyProperty.
3. Maneje OnCreateNodeClass para la vista de árbol para especificar que se debe
crear su clase de nodo.
4. Exponer algo así como la propiedad TreeView1_SelectedNode en el nivel del
formulario. Esto sería de tipo TMyTreeNode.

1. Maneje OnChange de la vista en árbol para escribir en SelectedNode el valor


del nodo que está seleccionado.
2. Use TreeView1_Selected.myProperty para leer o escribir un nuevo valor
personalizado.
Aquí está el código fuente completo (TButton: "Button1" y TTreeView: "TreeView1"
en un formulario):

> unidad UnitSample; la interfaz usa Windows, Mensajes, SysUtils, Variantes,


Clases, Gráficos, Controles, Formularios, Diálogos, ComCtrls,
StdCtrls; tipo TMyTreeNode = clase (TTreeNode) private fMyProperty:
cadena; propiedad pública MyProperty: string
read fMyProperty write fMyProperty; fin; TMyTreeNodeForm = clase (TForm)
TreeView1: TTreeView; Button1: TButton; procedimiento FormCreate (Sender:
TObject); procedimiento TreeView1CreateNodeClass (Remitente: TCustomTreeView;
var NodeClass: TTreeNodeClass); procedimiento TreeView1Change (Sender: TObject;
Node: TTreeNode); procedimiento Button1Click (Sender:
TObject); private fTreeView1_Selected: TMyTreeNode; Propiedad TreeView1_Selected:
TMyTreeNode read fTreeView1_Selected; public {Public
declarations} end ; var MyTreeNodeForm: TMyTreeNodeForm; implementación {$ R
* .dfm} procedimiento TMyTreeNodeForm.Button1Click (Sender: TObject); begin //
cambie el valor de MyProperty en algún botón, haga clic en Assigned
(TreeView1_Selected) luego TreeView1_Selected.MyProperty: = 'new value'; fin ; //
forma el procedimiento OnCreate TMyTreeNodeForm.FormCreate (Sender:
TObject); var tn: TTreeNode; cnt: entero; comience // complete algunos
elementos TreeView1.Items.Clear; para cnt: = 0 a 9 do begin tn: =
TreeView1.Items.AddChild ( nil , IntToStr (cnt)); // agrega valores predeterminados de
MyProperty TMyTreeNode (tn) .MyProperty: = 'this is node' + IntToStr
(cnt); fin ; fin ; // TreeView
OnChange procedure TMyTreeNodeForm.TreeView1Change (Sender: TObject; Node:
TTreeNode); begin fTreeView1_Selected: = TMyTreeNode (Node); fin ; // TreeView
OnCreateNodeClass procedimiento TMyTreeNodeForm.TreeView1CreateNodeClass
(Sender: TCustomTreeView; var NodeClass: TTreeNodeClass); begin NodeClass: =
TMyTreeNode; fin ; fin
Esta vez, la propiedad Data de la clase TTreeNode no se usa. Más bien, extiende
la clase TTreeNode para tener su propia versión de un nodo de árbol:
TMyTreeNode.

Al utilizar el evento OnCreateNodeClass de la vista de árbol, crea un nodo de su


clase personalizada en lugar de la clase TTreenode estándar.

Finalmente, si está listo para usar vistas de árbol en sus aplicaciones, eche un
vistazo a VirtualTreeView.

Cómo buscar archivos y carpetas con


Delphi
• by Zarko Gajic
• Al buscar archivos, a menudo es útil y necesario buscar a través de
subcarpetas. Aquí, vea cómo usar la fuerza de Delphi para crear un
proyecto simple, pero poderoso, de búsqueda de todos los archivos
coincidentes.

• Proyecto de búsqueda de máscara de archivo / carpeta


• El siguiente proyecto no solo le permite buscar archivos a través de
subcarpetas, sino que también le permite determinar fácilmente los
atributos del archivo, como Nombre, Tamaño, Fecha de modificación, etc.
para que pueda ver cuándo invocar el cuadro de diálogo Propiedades de
archivo desde el Explorador de Windows .

• En particular, demuestra cómo buscar de forma recursiva a través de


subcarpetas y ensamblar una lista de archivos que coincidan con una
determinada máscara de archivo. La técnica de recursión se define como
una rutina que se llama a sí misma en el medio de su código.

• Para comprender el código del proyecto, debemos familiarizarnos con los


siguientes tres métodos definidos en la unidad SysUtils: FindFirst, FindNext
y FindClose.

• FindFirst
• > función FindFirst ( const Path: string; Attr: Integer; var Rec: TSearchRec): Integer;

• FindFirst es la llamada de inicialización para iniciar un procedimiento


detallado de búsqueda de archivos utilizando llamadas a la API de
Windows . La búsqueda busca archivos que coincidan con el especificador
de ruta. La ruta generalmente incluye caracteres comodín (* y?). El
parámetro Attr contiene combinaciones de atributos de archivo para
controlar la búsqueda. Las constantes de atributo de archivo reconocidas
en Attr son: faAnyFile (cualquier
archivo), faDirectory (directorios), faReadOnly (archivos de solo
lectura), faHidden (archivos ocultos), faArchive (archivos de
almacenamiento), faSysFile (archivos de sistema) y faVolumeID (archivos
de ID de volumen )

• Si FindFirst encuentra uno o más archivos coincidentes, devuelve 0 (o un


código de error para la falla, generalmente 18) y rellena la Rec con
información sobre el primer archivo coincidente. Para continuar la
búsqueda, debemos usar el mismo registro TSearcRec y pasarlo a la
función FindNext. Cuando se completa la búsqueda, se debe llamar al
procedimiento FindClose para liberar recursos internos de Windows.

• TSearchRec es un registro definido como:


• > escriba TSearchRec = record Time: Integer; Tamaño: Entero; Attr:
Entero; Nombre: TFileName; ExcludeAttr: Entero; FindHandle: Thandle; FindData:
TWin32FindData; fin ;

• Cuando se encuentra el primer archivo, el parámetro Rec se llena y el


proyecto puede usar los siguientes campos (valores).
. Attr , los atributos del archivo como se describe arriba.
. El nombre contiene una cadena que representa un nombre de archivo, sin
información de ruta
. Tamaño en bytes del archivo encontrado.
. Time almacena la fecha y hora de modificación del archivo como una
fecha de archivo.
. FindData contiene información adicional, como la hora de creación del
archivo, la última hora de acceso y los nombres de archivo largo y corto.

• EncontrarSiguiente
• > función FindNext ( var Rec: TSearchRec): entero;

• La función FindNext es el segundo paso en el procedimiento detallado de


búsqueda de archivos. Debe pasar el mismo registro de búsqueda (Rec)
que ha creado la llamada a FindFirst. El valor de retorno de FindNext es
cero para el éxito o un código de error para cualquier error.

• EncontrarCerrar
• > procedimiento FindClose ( var Rec: TSearchRec);

• Este procedimiento es la llamada de terminación requerida para FindFirst /


FindNext.

• Búsqueda de coincidencia de máscara recurrente de archivo en Delphi


• Este es el proyecto "Buscar archivos" tal como aparece en tiempo de
ejecución.

• Los componentes más importantes en el formulario son dos cuadros de


edición , un cuadro de lista, una casilla de verificación y un botón. Los
cuadros de edición se utilizan para especificar la ruta en la que desea
buscar y una máscara de archivo. Los archivos encontrados se muestran
en el cuadro de lista y si la casilla de verificación está marcada, todas las
subcarpetas se analizan en busca de archivos coincidentes.

• A continuación se muestra el pequeño fragmento de código del proyecto,


solo para mostrar que la búsqueda de archivos con Delphi es tan fácil como
puede ser:

• > procedimiento FileSearch ( const PathName, FileName: string ); var Rec:


TSearchRec; Ruta: cadena; begin Path: = IncludeTrailingPathDelimiter
(PathName); si FindFirst (Path + FileName, faAnyFile - faDirectory, Rec) =
0, entonces intenta repetir ListBox1.Items.Add (Path + Rec.Name); hasta FindNext
(Rec) <> 0; finalmente FindClose (Rec); fin ; ... {todo el código, particularmente la
llamada a función recursiva se puede encontrar (descargar) en el código fuente del
proyecto} ... fin ;

Comprender el parámetro del remitente


en Delphi Event Handlers
• by Zarko Gajic

Manejadores de eventos y el remitente

Eche un vistazo al siguiente controlador de eventos para el evento OnClick de un


botón (llamado "Button1"): > procedure TForm1.Button1Click ( Sender :
TObject); comenzar ... finalizar ; El método Button1Click toma un puntero a un
TObject llamado Sender. Cada controlador de eventos, en Delphi, tendrá al menos
un parámetro de remitente. Cuando se hace clic en el botón, se llama al
controlador de eventos (Button1Click) para el evento OnClick .
El parámetro "Remitente" hace referencia al control que se utilizó para llamar al
método.

Si hace clic en el control Button1, haciendo que se llame al método Button1Click,


se pasa una referencia o puntero al objeto Button1 a Button1Click en el parámetro
llamado Sender.

Compartamos un poco de código

El parámetro Sender, cuando se usa correctamente, puede brindar una cantidad


increíble de flexibilidad en nuestro código. Lo que hace el parámetro Sender es
saber qué componente desencadenó el evento. Esto facilita el uso del mismo
controlador de eventos para dos componentes diferentes.
Por ejemplo, supongamos que queremos tener un botón y un elemento de menú
para hacer lo mismo. Sería una tontería tener que escribir el mismo controlador de
eventos dos veces.

Para compartir un controlador de eventos en Delphi, haga lo siguiente:

1. Escriba el controlador de eventos para el primer objeto (por ejemplo, botón en


la barra de acceso rápido)
2. Seleccione el nuevo objeto u objetos, sí, más de dos pueden compartir (por
ejemplo, MenuItem1)
3. Vaya a la página del evento en el Inspector de Objetos.
4. Haga clic en la flecha hacia abajo junto al evento para abrir una lista de
controladores de eventos escritos anteriormente. (Delphi le dará una lista de
todos los controladores de eventos compatibles que existen en el formulario)

1. Seleccione el evento de la lista desplegable. (por ejemplo, Button1Click)


Lo que hemos hecho aquí es crear un único método de manejo de eventos que
maneje el evento OnClick tanto de un botón como de un elemento del menú.
Ahora, todo lo que tenemos que hacer (en este controlador de eventos
compartidos) es distinguir qué componente llamó al controlador. Por ejemplo,
podríamos tener un código como este: > procedure TForm1.Button1Click (Sender:
TObject); begin {código tanto para un botón como para un elemento de
menú} ... {algún código específico:} si Sender = Button1 luego ShowMessage
('Button1 clicked!') else si Sender = MenuItem1 luego ShowMessage ('MenuItem1
hecho clic!') else ShowMessage ('??? clicked!'); fin ; En general, verificamos si el
emisor es igual al nombre del componente.
Nota: el segundo más en la instrucción if-then-else maneja la situación cuando ni
el Button1 ni el MenuItem1 han causado el evento. Pero, quién más podría llamar
al controlador, podrías preguntar. Pruebe esto (necesitará un segundo botón:
Button2):

> procedure TForm1.Button2Click (Sender: TObject); Comience Button1Click


(Button2); {esto dará como resultado: '??? hecho clic! '} fin ;

IS y AS

Como el remitente es del tipo TObject, cualquier objeto se puede asignar al


remitente. El valor de Sender siempre es el control o componente que responde al
evento. Podemos probar al remitente para encontrar el tipo de componente o
control que llamó al controlador de eventos utilizando la palabra reservada. Por
ejemplo, > si
el remitente es TButton, luego DoSomething else DoSomethingElse ; Para rayar la
superficie de los operadores "is" y "as", agregue un cuadro de edición (llamado
Edit1) al formulario y coloque el siguiente código en el controlador de eventos
OnExit: > procedure TForm1.Edit1Exit (Sender: TObject); comenzar Button1Click
(Edit1); fin ; Ahora cambie ShowMessage ('??? clicked!'); parte en el controlador de
eventos Button1 OnClick para: > {... else} comenzar si el remitente es TButton
y luego ShowMessage ('¡Algún otro botón activó este evento!') else si
el remitente es TEdit y luego el remitente como TEdit comienza Text: = ' Edit1Exit
ha sucedido '; Ancho: = ancho * 2; Altura: = Altura * 2; fin {comenzar con} fin ; Ok,
veamos: si hacemos clic en el Botón1, ¡el 'Botón1 hizo clic!' aparecerá, si hacemos
clic en el MenuItem1, se hace clic en 'MenuItem1!' aparecerá. Sin embargo, si
hacemos clic en Buton2, el botón '¡Otro botón activó este evento!' aparecerá un
mensaje, pero ¿qué pasará cuando salga del cuadro Editar1? Te dejaré esto a ti.

Conclusión

Como podemos ver, el parámetro del remitente puede ser muy útil cuando se usa
correctamente. Supongamos que tenemos un montón de cuadros de edición y
etiquetas que comparten el mismo controlador de eventos. Si queremos saber
quién desencadenó el evento y actuar, tendremos que tratar con las variables
Object. Pero, dejemos esto para alguna otra ocasión.

BPL vs. DLL


• by Zarko Gajic

Introducción a los paquetes; ¡Los BPL son DLL especiales!

Cuando escribimos y compilamos una aplicación Delphi, normalmente generamos


un archivo ejecutable, una aplicación de Windows independiente. A diferencia de
Visual Basic, por ejemplo, Delphi produce aplicaciones envueltas en archivos exe
compactos, sin necesidad de bibliotecas de tiempo de ejecución voluminosas
(DLL).

Intente esto: inicie Delphi y compile ese proyecto predeterminado con un


formulario en blanco, esto producirá un archivo ejecutable de aproximadamente
385 KB (Delphi 2006).

Ahora vaya a Proyecto - Opciones - Paquetes y marque la casilla de verificación


'Construir con paquetes de tiempo de ejecución'. Compilar y ejecutar Voila, el
tamaño del exe ahora es de alrededor de 18 KB.

De forma predeterminada, la opción 'Generar con paquetes de tiempo de


ejecución' está desmarcada y cada vez que creamos una aplicación Delphi, el
compilador vincula todo el código que su aplicación necesita para ejecutar
directamente en el archivo ejecutable de la aplicación . Su aplicación es un
programa independiente y no requiere ningún archivo de soporte (como archivos
DLL); es por eso que los exe de Delphi son tan grandes.

Una forma de crear programas Delphi más pequeños es aprovechar las


'bibliotecas de paquetes de Borland' o BPL en resumen.
¿Qué es un paquete?
En pocas palabras, un paquete es una biblioteca de enlace dinámico especial utilizada
por las aplicaciones Delphi , Delphi IDE, o ambas. Los paquetes están disponibles en
Delphi 3 (!) Y superior.

Los paquetes nos permiten colocar porciones de nuestra aplicación en módulos


separados que se pueden compartir en múltiples aplicaciones.

Los paquetes también brindan un medio para instalar componentes


(personalizados) en la plataforma VCL de Delphi.

Por lo tanto, Delphi básicamente puede hacer dos tipos de paquetes:

▪ Paquetes en tiempo de ejecución: brindan funcionalidad cuando un usuario ejecuta


una aplicación; funcionan de manera muy similar a las DLL estándar.
▪ Paquetes de tiempo de diseño: se usan para instalar componentes en Delphi IDE y para
crear editores de propiedades especiales para componentes personalizados.
Los paquetes de diseño contienen componentes, editores de propiedades y componentes,
expertos, etc., necesarios para el diseño de la aplicación en Delphi IDE. Este tipo de
paquete solo lo usa Delphi y nunca se distribuye con sus aplicaciones.
A partir de este punto, este artículo se ocupará de los paquetes de tiempo de
ejecución y de cómo pueden ayudar al programador de Delphi.

Un tru malo : no se requiere que seas un desarrollador de componentes


Delphi para aprovechar los paquetes. Los programadores principiantes de Delphi
deberían intentar trabajar con paquetes, comprenderán mejor cómo funcionan los
paquetes y Delphi.

Cuándo y cuándo no utilizar Paquetes


Algunos dicen que las DLL son una de las funciones más útiles y potentes que se hayan
agregado al sistema operativo Windows. Muchas aplicaciones que se ejecutan al mismo
tiempo causan problemas de memoria en sistemas operativos como Windows. Muchos de
estos programas realizan tareas similares, pero cada uno contiene un código para realizar
el trabajo en sí. Es entonces cuando los archivos DLL se vuelven potentes, le permiten
quitar todo ese código de los ejecutables y ponerlo en un entorno compartido llamado
DLL. Probablemente, el mejor ejemplo de DLL en acción es el sistema operativo MS
Windows con su API, nada más que un conjunto de DLL.

Los archivos DLL son más comúnmente utilizados como colecciones de


procedimientos y funciones que otros programas pueden llamar.

Además de escribir archivos DLL con rutinas personalizadas, podemos colocar un


formulario completo de Delphi en una DLL (por ejemplo, un formulario AboutBox).
Otra técnica común es almacenar nada más que recursos en DLL. Más
información sobre cómo funciona Delphi con DLL encuentra en este artículo: DLL
y Delphi .

Antes de pasar a la comparación entre DLL y BPL, debemos comprender dos


formas de vincular el código en un archivo ejecutable: enlace estático y dinámico.

La vinculación estática significa que cuando se compila un proyecto Delphi, todo


el código que requiere su aplicación está directamente relacionado con el archivo
ejecutable de la aplicación. El archivo exe resultante contiene todo el código de
todas las unidades que están involucradas en un proyecto. Demasiado código,
podrías decir. De forma predeterminada, usa la cláusula para una nueva lista de
unidades de formulario de más de 5 unidades (Windows, Mensajes, SysUtils, ...).

Sin embargo, el enlazador Delphi es lo suficientemente inteligente como para


vincular solo el mínimo de código en las unidades realmente utilizadas por un
proyecto. Con enlaces estáticos, nuestra aplicación es un programa independiente
y no requiere ningún paquete de soporte o DLL (olvide los componentes BDE y
ActiveX por ahora). En Delphi, la vinculación estática es el valor predeterminado.

La vinculación dinámica es como trabajar con DLL estándar. Es decir, el enlace


dinámico proporciona funcionalidad a múltiples aplicaciones sin vincular el código
directamente a cada aplicación; todos los paquetes necesarios se cargan en
tiempo de ejecución. Lo mejor de los enlaces dinámicos es que la carga de
paquetes por parte de su aplicación es automática. No tiene que escribir código
para cargar los paquetes ni tiene que cambiar su código.

Simplemente marque la casilla de verificación 'Construir con paquetes de tiempo


de ejecución' que se encuentra en el Proyecto | Cuadro de diálogo de opciones. La
próxima vez que construya su aplicación, el código de su proyecto se vinculará
dinámicamente a los paquetes de tiempo de ejecución en lugar de tener unidades
vinculadas estáticamente en su archivo ejecutable.

Tamaño de archivo: obtenga el tamaño de


un archivo en bytes usando Delphi
• by Zarko Gajic
• La función FileSize devuelve el tamaño de un archivo, en bytes, un
resultado útil para ciertas aplicaciones de entrega de archivos dentro de un
programa Delphi.

• Obtener tamaño de archivo


• La función FileSize devuelve el tamaño de un archivo en bytes; la función
devuelve -1 si el archivo no se encontró.
• > // devuelve el tamaño del archivo en bytes o -1 si no se encuentra.
función FileSize (fileName: wideString): Int64;
var
sr: TSearchRec;
empezar
si FindFirst (fileName, faAnyFile, sr) = 0, entonces
resultado: = Int64 (sr.FindData.nFileSizeHigh) shl Int64 (32) + Int64
(sr.FindData.nFileSizeLow)
más
resultado: = -1;
FindClose (sr);
fin ;

• Cuando tiene el tamaño de un archivo en bytes, puede formatear el tamaño


para mostrar (Kb, Mb, Gb) para ayudar a los usuarios finales a comprender
los datos sin tener que convertir unidades.

Tipos de datos ordinales en Delphi


• by Zarko Gajic
• El lenguaje de programación de Delphi es un ejemplo de un lenguaje
fuertemente tipado. Esto significa que todas las variables deben ser de
algún tipo. Un tipo es esencialmente un nombre para un tipo de datos.
Cuando declaramos una variable, debemos especificar su tipo, que
determina el conjunto de valores que la variable puede contener y las
operaciones que se pueden realizar en ella.

• Muchos de los tipos de datos integrados de Delphi, como Integer o String,


se pueden refinar o combinar para crear nuevos tipos de datos.

• En este artículo, veremos cómo crear tipos de datos ordinales


personalizados en Delphi .

• Tipos Ordinales
• Las características definitorias de los tipos de datos ordinales son: deben
consistir en un número finito de elementos y deben ordenarse de alguna
manera.

• Los ejemplos más comunes de tipos de datos ordinales son todos los tipos
enteros, así como los tipos Char y Boolean. Más precisamente, Object
Pascal tiene doce tipos ordinales predefinidos: Integer, Shortint, Smallint,
Entero largo, Byte, Word, Cardinal, Boolean, ByteBool, WordBool, LongBool
y Char. También hay otras dos clases de tipos ordinales definidos por el
usuario: tipos enumerados y tipos de subrango.
• En cualquier tipo ordinal, debe tener sentido moverse hacia atrás o hacia
adelante al siguiente elemento. Por ejemplo, los tipos reales no son
ordinales porque moverse hacia atrás o hacia adelante no tiene sentido: la
pregunta "¿Cuál es el siguiente real después de 2.5?" no tiene sentido.

• Como, por definición, cada valor, excepto el primero, tiene un predecesor


único y cada valor, excepto el último, tiene un único sucesor, se usan
varias funciones predefinidas cuando se trabaja con tipos ordinales:

Función Efecto

Ord (X) Da el índice del elemento

Pred (X) Va al elemento enumerado antes de X en el tipo

Succ (X) Va al elemento enumerado después de X en el tipo

Dec (X; n) Mueve n elementos hacia atrás (si se omite n mueve 1 elemento hacia atrás)

Inc (X; n) Mueve n elementos hacia adelante (si se omite n mueve 1 elemento hacia adelante)

Bajo (X) Devuelve el valor más bajo en el rango del tipo de datos ordinales X.

Alto (X) Devuelve el valor más alto en el rango del tipo de datos ordinales X.

Por ejemplo, High (Byte) devuelve 255 porque el valor más alto de tipo Byte
es 255 y Succ (2) devuelve 3 porque 3 es el sucesor de 2.

• Nota: Si tratamos de usar Succ cuando en el último elemento, Delphi


generará una excepción de tiempo de ejecución si la verificación de rango
está activada.

• Tipos de datos enumerados


• La forma más fácil de crear un nuevo ejemplo de tipo ordinal es
simplemente enumerar un grupo de elementos en algún orden. Los valores
no tienen un significado inherente, y su ordinalidad sigue la secuencia en la
que se enumeran los identificadores. En otras palabras, una enumeración
es una lista de valores.

• tipo TWeekDays = (lunes, martes, miércoles, jueves, viernes, sábado, domingo);

• Una vez que definimos un tipo de datos enumerados, podemos declarar


que las variables son de ese tipo:

• var SomeDay: TWeekDays;

• El propósito principal de un tipo de datos enumerados es dejar en claro qué


datos manipulará su programa. Un tipo enumerado es en realidad una
forma abreviada de asignar valores secuenciales a las constantes. Dadas
estas declaraciones, el martes es una constante de tipo TWeekDays .

• Delphi nos permite trabajar con los elementos en un tipo enumerado


usando un índice que proviene del orden en el que se incluyeron. En el
ejemplo anterior: el lunes en la declaración de tipo TWeekDays tiene el
índice 0, el martes tiene el índice 1, y así en.

• Las funciones enumeradas en la tabla anterior nos permiten, por ejemplo,


usar Succ (viernes) para "ir a" sábado.

• Ahora podemos probar algo como:

• para SomeDay: = de lunes a domingo si Someday = Tuesday luego ShowMessage


('Tuesday is is');

• La Biblioteca de componentes visuales de Delphi usa tipos enumerados en


muchos lugares. Por ejemplo, la posición de un formulario se define de la
siguiente manera:

• TPosition = (poDesigned, poDefault, poDefaultPosOnly, poDefaultSizeOnly,


poScreenCenter);
• Usamos Posición (a través del Inspector de objetos) para obtener o
establecer el tamaño y la ubicación del formulario.

• Tipos de subrango
• En pocas palabras, un tipo de subrango representa un subconjunto de los
valores en otro tipo ordinal. En general, podemos definir cualquier subrango
comenzando con cualquier tipo ordinal (incluido un tipo enumerado
previamente definido) y usando un punto doble:

• tipo TWorkDays = lunes ... viernes;

• Aquí TWorkDays incluye los valores lunes, martes, miércoles, jueves y


viernes.

• Eso es todo, ¡ahora ve a enumerar!

Edite y visualice campos booleanos


usando CheckBox en DBGrid de Delphi
• by Zarko Gajic
• Una serie de artículos titulados Agregar componentes a un DBGrid trata de
colocar casi cualquier control Delphi (componente visual) en una celda de
un DGBrid . La idea es crear interfaces de usuario visualmente más
atractivas para editar campos dentro de un DBGrid: un ComboBox para
listas desplegables; un DateTimePicker (calendario) para valores de fecha;
una casilla de verificación para campos booleanos.

• CheckBox para campos booleanos


• El artículo CheckBox dentro de un DBGrid proporciona un método para usar un
control de casilla de verificación para editar y mostrar valores para campos
booleanos.

• Como notó Rene van der Heijden, la solución es bastante larga, y no


funciona, al menos no cuando se usa el mouse para hacer clic en las
casillas de verificación.

• René sugiere un enfoque más sencillo que solo necesite dos controladores
pares: OnCellClick y OnCustomDrawCell para su control DBGrid:

• > // Evento OnCellClik de un procedimiento DBGrid1 TForm.DBGrid1


CellClick (Columna: TColumn); begin if (Column.Field.DataType =
ftBoolean) luego comience {alternar entre True y
False} Column.Grid.DataSource.DataSet.Edit; Column.Field.Value:
= no Column.Field.AsBoolean; {publicación inmediata: compruebe usted mismo si
desea esto} Column.Grid.DataSource.DataSet.Post; {puede agregar funciones
adicionales aquí, para procesarlas una vez que se haya realizado el
cambio} fin ; fin ; // Evento OnDrawColumnCell de un procedimiento DBGrid1
TForm.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect; DataCol: Entero;
Columna: TColumn; Estado:
TGridDrawState); const CtrlState: array [booleano] de entero =
(DFCS_BUTTONCHECK,
DFCS_BUTTONCHECK o DFCS_CHECKED); begin if (Column.Field.DataType =
ftBoolean) luego comience DBGrid1.Canvas.FillRect (Rect); si VarIsNull
(Column.Field.Value) entonces DrawFrameControl (DBGrid1.Canvas.Handle, Rect,
DFC_BUTTON, DFCS_BUTTONCHECK o
DFCS_INACTIVE) {grayed} else DrawFrameControl (DBGrid1.Canvas.Handle, Rect,
DFC_BUTTON, CtrlState [Column.Field.AsBoolean] ); {marcado o no
marcado} final ; fin ;

Cómo usar las casillas de verificación en


un DBGrid
• by Zarko Gajic
• Haga que su aplicación sea más atractiva visualmente

• Existen numerosas formas y razones para personalizar el resultado de


un DBGrid en Delphi . Una forma es agregar casillas de verificación para
que el resultado sea más atractivo visualmente.

• De forma predeterminada, si tiene un campo booleano en su conjunto de


datos, DBGrid los muestra como "Verdadero" o "Falso" dependiendo del
valor del campo de datos. Sin embargo, parece mucho mejor si elige usar
un control de casilla de verificación "verdadero" para habilitar la edición de
los campos.

• Crear una aplicación de muestra


• Inicie un nuevo formulario en Delphi y coloque un TDBGrid, TADOTable y
TDOConnection, TDataSource.

• Deje todos los nombres de los componentes tal como están cuando se
colocaron primero en el formulario (DBGrid1, ADOQuery1, AdoTable 1,
etc.). Utilice el Inspector de Objetos para establecer una propiedad
ConnectionString del componente ADOConnection1 (TDOConnection) para
que apunte a la base de datos de muestra QuickiesContest.mdb MS
Access.
• Conecte DBGrid1 a DataSource1, DataSource1 a ADOTable1, y finalmente
a ADOTable1 a ADOConnection1. La propiedad ADOTable1 TableName
debe señalar a la tabla Artículos (para hacer que DBGrid muestre los
registros de la tabla Artículos).

• Si ha establecido todas las propiedades correctamente, cuando ejecuta la


aplicación (dado que la propiedad Activo del componente ADOTable1 es
Verdadero) debería ver, de forma predeterminada, que el DBGrid muestra
el valor del campo booleano como "Verdadero" o "Falso" dependiendo en el
valor del campo de datos.

• CheckBox en una DBGrid


• Para mostrar una casilla de verificación dentro de una celda de un DBGrid,
necesitaremos tener uno disponible para nosotros en tiempo de ejecución.

• Seleccione la página "Controles de datos" en la Paleta de componentes y


elija un TDBCheckbox . Coloque uno en cualquier lugar del formulario, no
importa dónde, ya que la mayoría de las veces será invisible o flotante en la
cuadrícula.

• Consejo: TDBCheckBox es un control de datos que permite al usuario


seleccionar o anular la selección de un solo valor, que es apropiado para
los campos booleanos.

• A continuación, establezca su propiedad Visible en False. Cambie la


propiedad Color de DBCheckBox1 al mismo color que DBGrid (para que se
mezcle con DBGrid) y elimine el Título.

• Lo que es más importante, asegúrese de que DBCheckBox1 esté


conectado al DataSource1 y al campo correcto.

• Tenga en cuenta que todos los valores de propiedad de DBCheckBox1


anteriores se pueden establecer en el evento OnCreate del formulario como
este:

• procedure TForm1.FormCreate (Sender:


TObject); comenzar DBCheckBox1.DataSource: = DataSource1;
DBCheckBox1.DataField: = 'Ganador'; DBCheckBox1.Visible: = False;
DBCheckBox1.Color: = DBGrid1.Color; DBCheckBox1.Caption: = ''; // explicado más
adelante en el artículo DBCheckBox1.ValueChecked: = 'Yes a Winner!';
DBCheckBox1.ValueUnChecked: = 'No esta vez.'; fin ;

• Lo que viene a continuación es la parte más interesante. Mientras editamos


el campo booleano en DBGrid, necesitamos asegurarnos de que
DBCheckBox1 esté arriba ("flotante") de la celda en el DBGrid que muestra
el campo booleano.
• Para el resto de las celdas (no enfocadas) que llevan los campos booleanos
(en la columna "Ganador"), necesitamos proporcionar alguna
representación gráfica del valor booleano (Verdadero / Falso).

• Esto significa que necesita al menos dos imágenes para dibujar: una para el
estado comprobado (valor verdadero) y otra para el estado no verificado
(valor falso).

• La forma más sencilla de lograr esto es utilizar la función


DrawFrameControl de la API de Windows para dibujar directamente en el
lienzo de DBGrid.

• Aquí está el código en el controlador de eventos OnDrawColumnCell de


DBGrid que ocurre cuando la grilla necesita pintar una celda.

• procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect;


DataCol: Entero; Columna: TColumn; Estado:
TGridDrawState); const IsChecked: array [Boolean] de Integer =
(DFCS_BUTTONCHECK, DFCS_BUTTONCHECK o DFCS_CHECKED); var DrawState:
entero; DrawRect: TRect; comience if (gdFocused en State)
y luego comience if (Column.Field.FieldName = DBCheckBox1.DataField)
y luego comience DBCheckBox1.Left: = Rect.Left + DBGrid1.Left + 2;
DBCheckBox1.Top: = Rect.Top + DBGrid1.top + 2; DBCheckBox1.Width: =
Rect.Right - Rect.Left; DBCheckBox1.Height: = Rect.Bottom - Rect.Top;
DBCheckBox1.Visible: = Verdadero; end end else begin if (Column.Field.FieldName
= DBCheckBox1.DataField) luego comienza DrawRect: = Rect; InflateRect
(DrawRect, -1, -1); DrawState: = ISChecked [Column.Field.AsBoolean];
DBGrid1.Canvas.FillRect (Rect); DrawFrameControl (DBGrid1.Canvas.Handle,
DrawRect, DFC_BUTTON, DrawState); fin ; fin ; fin ;

• Para finalizar este paso, debemos asegurarnos de que DBCheckBox1 sea


invisible cuando salgamos de la celda:

• procedure TForm1.DBGrid1ColExit (Sender:


TObject); comience si DBGrid1.SelectedField.FieldName =
DBCheckBox1.DataField entonces DBCheckBox1.Visible: = False end ;

• Solo necesitamos dos eventos más para manejar.

• Tenga en cuenta que cuando se está en el modo de edición, todas las


pulsaciones de teclas van a la celda de DBGrid, debemos asegurarnos de
que se envíen al CheckBox. En el caso de un CheckBox, nos interesan
principalmente las teclas [Tab] y [Space]. [Tab] debería mover el foco de
entrada a la celda siguiente, y [Espacio] debería alternar el estado de
CheckBox.
• procedure TForm1.DBGrid1KeyPress (Sender: TObject; var Key:
Char); comience si (clave = Chr (9)) luego
Salga ; if (DBGrid1.SelectedField.FieldName =
DBCheckBox1.DataField) entonces comienza DBCheckBox1.SetFocus;
SendMessage (DBCheckBox1.Handle, WM_Char, palabra (clave), 0); fin ; fin ;

• Podría ser apropiado que el título de la casilla de verificación cambie a


medida que el usuario marca o desmarca la casilla. Tenga en cuenta que
DBCheckBox tiene dos propiedades (ValueChecked y ValueUnChecked)
utilizadas para especificar el valor de campo representado por la casilla de
verificación cuando está marcada o desmarcada.

• Esta propiedad ValueChecked contiene "Sí, un ganador!", Y


ValueUnChecked equivale a "No esta vez".

• procedimiento TForm1.DBCheckBox1Click (Sender:


TObject); comenzar si DBCheckBox1.Checked entonces DBCheckBox1.Caption: =
DBCheckBox1.ValueChecked else DBCheckBox1.Caption: =
DBCheckBox1.ValueUnChecked; fin;

• Ejecute el proyecto y verá las casillas de verificación en toda la columna del


campo Ganador.

Visualización y edición de campos MEMO


en TDBGrid de Delphi
• by Zarko Gajic

Si está desarrollando aplicaciones de bases de datos con tablas que contienen


campos MEMO, notará que, de forma predeterminada, el componente TDBGrid no
muestra los contenidos de un campo MEMO dentro de una celda DBGrid.

Este artículo proporciona una idea de cómo resolver el problema de este


TMemoField (con algunos trucos más) ...

TMemoField

Los campos de notas se utilizan para representar texto extenso o combinaciones


de texto y números. Al crear aplicaciones de bases de datos utilizando Delphi, el
objeto TMemoField se utiliza para representar un campo memo en un conjunto de
datos.
TMemoField encapsula el comportamiento fundamental común a los campos que
contienen datos de texto o longitud arbitraria. En la mayoría de las bases de datos,
el tamaño del campo Memo está limitado por el tamaño de la base de datos.

Si bien puede visualizar los contenidos de un campo MEMO en un componente


TDBMemo, por diseño, TDBGrid solo mostrará "(Memo)" para el contenido de
dichos campos.

Para mostrar realmente algo de texto (del campo MEMO) en la celda DBGrid
apropiada, solo necesitará agregar una línea simple de código ...

Para el propósito de la próxima discusión, digamos que tiene una tabla de base de
datos llamada "TestTable" con al menos un campo MEMO llamado "Datos".

OnGetText

Para mostrar el contenido de un campo MEMO en DBGrid, debe adjuntar una


línea de código simple en el evento OnGetText del campo. La forma más fácil de
crear el controlador de eventos OnGetText es usar el editor Fields en el momento
del diseño para crear un componente de campo persistente para el campo memo:

1. Conecte su componente descendiente TDataset (TTable, TQuery, TADOTable,


TADOQuery ....) a la tabla de la base de datos "TestTable".
2. Haga doble clic en el componente del conjunto de datos para abrir el editor
Fields
3. Agregue el campo MEMO a la lista de campos persistentes
4. Seleccione el campo MEMO en el editor Fields
5. Activar la pestaña Eventos en el Inspector de Objetos

1. Haga doble clic en el evento OnGetText para crear el controlador de eventos


Agregue la siguiente línea de código (en cursiva a continuación):

procedure TForm1.DBTableDataGetText (Sender: TField; var Text: String;


DisplayText: Boolean); begin Text: = Copy (DBTableData.AsString, 1, 50);
Nota: el objeto del conjunto de datos se llama "DBTable", el campo MEMO se
llama "DATA" y, por lo tanto, de forma predeterminada, el TMemoField conectado
al campo de la base de datos MEMO se llama "DBTableData". Al
asignar DBTableData.AsString al parámetro de texto del evento OnGetText, le
decimos a Delphi que muestre TODO el texto del campo MEMO en una celda
DBGrid.
También puede adaptar DisplayWidth del campo memo a un valor más apropiado.
Nota: dado que los campos MEMO pueden ser bastante GRANDES, es una buena
idea mostrar solo una parte. En el código anterior, solo se muestran los primeros
50 caracteres.

Editando en un formulario separado

Por defecto, TDBGrid no permite editar campos MEMO. Si desea habilitar la


edición "en el lugar", puede agregar un código para reaccionar en una acción del
usuario que muestra una ventana separada que permite editar utilizando un
componente TMemo.
En aras de la simplicidad, abriremos una ventana de edición cuando presione "on"
en un campo MEMO en un DBGrid.
Usemos el evento KeyDown de un componente DBGrid:

procedure TForm1.DBGrid1KeyDown (Sender: TObject; var Clave: Word; Shift: TShiftState); comience si Key =
VK_RETURN luego comience si DBGrid1.SelectedField = DBTableData y luego con TMemoEditorForm.Create
( nil ) intente DBMemoEditor.Text: = DBTableData.AsString; ShowModal; DBTable.Edit; DBTableData.AsString: =
DBMemoEditor.Text; finalmente gratis; fin ; fin ; fin ;

Nota 1: el "TMemoEditorForm" es un formulario secundario que contiene solo un


componente: "DBMemoEditor" (TMemo).
Nota 2: el "TMemoEditorForm" se eliminó de la lista "Crear automáticamente
formularios" en la ventana de diálogo Opciones del proyecto.

Veamos qué sucede en el controlador de eventos KeyDown de DBGrid1:

1. Cuando un usuario presiona la tecla ENTER (estamos comparando el parámetro


Key con el código de tecla virtual VK_RETURN) [Key = VK_RETURN],

1. Si el campo seleccionado actualmente en DBGrid es nuestro campo MEMO


(DBGrid1.SelectedField = DBTableData),
2. Creamos el TMemoEditorForm [TMemoEditorForm.Create (nil)],
3. Envíe el valor del campo MEMO al componente TMemo [DBMemoEditor.Text: =
DBTableData.AsString],
4. Mostrar el formulario modalmente [ShowModal],
5. Cuando un usuario finaliza la edición y cierra el formulario, debemos poner el
dataste en el modo de edición [DBTable.Edit],
6. Para poder asignar el valor editado a nuestro campo MEMO
[DBTableData.AsString: = DBMemoEditor.Text].
Nota: si está buscando más artículos relacionados con TDBGrid y sugerencias de
uso, asegúrese de visitar: " TDBGrid to the MAX " colección de consejos.

Códigos de teclas virtuales utilizados por


Windows
• by Zarko Gajic
• Windows define constantes especiales para cada tecla que el usuario
puede presionar. Los códigos de clave virtual identifican varias claves
virtuales. Estas constantes se pueden usar para referirse a la pulsación de
tecla cuando se utilizan llamadas API Delphi y Windows o en un controlador
de eventos OnKeyUp o OnKeyDown . Las teclas virtuales consisten
principalmente en teclas de teclado reales, pero también incluyen
elementos "virtuales" como los tres botones del mouse. Delphi define todas
las constantes para los códigos de clave virtual de Windows en la unidad de
Windows.
• Estos son algunos de los artículos de Delphi que tratan sobre el teclado y
los códigos VK:
• Keyboard Symphony
Delphi para principiantes: familiarícese con los procedimientos de evento
OnKeyDown, OnKeyUp y onKeyPress para responder a varias acciones
clave o manejar y procesar caracteres ASCII junto con otras teclas de
propósito especial.
• Cómo traducir un código clave virtual en un personaje
Windows define constantes especiales para cada tecla que el usuario
puede presionar. Los códigos de clave virtual identifican varias claves
virtuales. En Delphi, los eventos OnKeyDown y OnKeyUp proporcionan el
nivel más bajo de respuesta del teclado. Para usar OnKeyDown o OnKeyUp
para probar las teclas que el usuario presiona, debe usar los códigos de
teclas virtuales para presionar la tecla. A continuación, se explica cómo
traducir el código de la tecla virtual al carácter de Windows correspondiente.
• Tócame, soy intocable
Interceptación de entrada de teclado para controles que no pueden recibir
el foco de entrada. Trabajando con ganchos de teclado de Delphi.
• Pestaña ENTRAR
Usando la tecla Enter como una tecla Tab con controles Delphi.
• Abortar un bucle presionando una tecla
Use VK_ESCAPE para abortar un bucle (for).
• Use las teclas de flecha para moverse entre los controles
Las teclas de flecha ARRIBA y ABAJO son prácticamente inútiles en los
controles de edición. Entonces, ¿por qué no usarlos para navegar entre
campos?
• Simulando pulsaciones de teclas desde código
Una práctica función para simular la presión de las teclas del teclado.
• La siguiente tabla muestra los nombres constantes simbólicos, valores
hexadecimales y equivalentes de teclado para los códigos de clave virtual
utilizados por Windows. Faltan algunas constantes específicas de Windows
2000 y OEM, la lista completa está disponible desde Microsoft. Los códigos
están listados en orden numérico.

Simbólico Valor
Teclado (o mouse) equivalente
nombre constante (hexadecimal)

VK_LBUTTON 01 Boton izquierdo del raton

VK_RBUTTON 02 Botón derecho del mouse

VK_CANCEL 03 Procesamiento de interrupción de control

VK_MBUTTON 04 Botón central del mouse (mouse de tres botone

VK_BACK 08 Tecla RETROCESO

VK_TAB 09 Tecla de tabulación

VK_CLEAR 0C Tecla CLEAR

VK_RETURN 0D Introducir clave


VK_SHIFT 10 Tecla Shift

VK_CONTROL 11 Tecla CTRL

VK_MENU 12 Tecla Alt

VK_PAUSE 13 Tecla PAUSE

VK_CAPITAL 14 Tecla BLOQ MAYÚS

VK_ESCAPE 1B Tecla ESC

VK_SPACE 20 BARRA ESPACIADORA

VK_PRIOR 21 Tecla PAGE UP

VK_NEXT 22 Tecla PÁGINA ABAJO

VK_END 23 Tecla END


VK_HOME 24 Llave de la casa

VK_LEFT 25 Tecla FLECHA IZQUIERDA

VK_UP 26 Tecla FLECHA ARRIBA

VK_RIGHT 27 Tecla FLECHA DERECHA

VK_DOWN 28 Tecla FLECHA ABAJO

VK_SELECT 29 Tecla SELECCIONAR

VK_PRINT 2A Tecla IMPRIMIR

VK_EXECUTE 2B Tecla EJECUTAR

VK_SNAPSHOT 2C PANTALLA IMPRIMIR tecla

VK_INSERT 2D Clave INS


VK_DELETE 2E Tecla DEL

VK_HELP 2F Tecla AYUDA

30 0 tecla

31 1 llave

32 2 llaves

33 3 llaves

34 4 teclas

35 5 teclas

36 6 teclas

37 7 teclas
38 8 teclas

39 Tecla 9

41 Una llave

42 Tecla B

43 Tecla C

44 Tecla D

45 Tecla E

46 Tecla F

47 Tecla G

48 Tecla H
49 Yo clave

4A J clave

4B Tecla K

4C L tecla

4D M clave

4E Tecla N

4F O clave

50 Tecla P

51 Tecla Q

52 Tecla R
53 Tecla S

54 Tecla T

55 Tecla U

56 Tecla V

57 Tecla W

58 Tecla X

59 Tecla Y

5A Tecla Z

VK_NUMPAD0 60 Teclado numérico 0 tecla

VK_NUMPAD1 61 Teclado numérico 1 tecla


VK_NUMPAD2 62 Teclado numérico 2 teclas

VK_NUMPAD3 63 Teclado numérico 3 teclas

VK_NUMPAD4 64 Teclado numérico 4 teclas

VK_NUMPAD5 sesenta y cinco Teclado numérico 5 teclas

VK_NUMPAD6 66 Teclado numérico 6 teclas

VK_NUMPAD7 67 Teclado numérico 7 teclas

VK_NUMPAD8 68 Teclado numérico 8 teclas

VK_NUMPAD9 69 Teclado numérico tecla 9

VK_SEPARATOR 6C Clave de separación

VK_SUBTRACT 6D Restar clave


VK_DECIMAL 6E Clave decimal

VK_DIVIDE 6F Divide la clave

VK_F1 70 Tecla F1

VK_F2 71 Tecla F2

VK_F3 72 Tecla F3

VK_F4 73 Tecla F4

VK_F5 74 Tecla F5

VK_F6 75 Tecla F6

VK_F7 76 Tecla F7

VK_F8 77 Tecla F8
VK_F9 78 Tecla F9

VK_F10 79 Tecla F10

VK_F11 7A Tecla F11

VK_F12 7B Tecla F12

VK_F13 7C Tecla F13

VK_F14 7D Tecla F14

VK_F15 7E Tecla F15

VK_F16 7F Tecla F16

VK_F17 80H Tecla F17

VK_F18 81H Tecla F18


VK_F19 82H Tecla F19

VK_F20 83H Tecla F20

VK_F21 84H Tecla F21

VK_F22 85H Tecla F22

VK_F23 86H Tecla F23

VK_F24 87H Tecla F24

VK_NUMLOCK 90 Tecla NUM LOCK

VK_SCROLL 91 Tecla SCROLL LOCK

VK_LSHIFT A0 Tecla MAYÚS a la izquierda

VK_RSHIFT A1 Tecla MAYÚS derecha


VK_LCONTROL A2 Tecla CONTROL izquierda

VK_RCONTROL A3 Tecla CONTROL DERECHA

VK_LMENU A4 Tecla MENÚ izquierda

VK_RMENU A5 Tecla MENÚ derecha

VK_PLAY FA Tecla de reproducción

VK_ZOOM pensión completa Tecla Zoom

Convierte RGB a TColor: obtén más


valores de TColor para Delphi
• by Zarko Gajic
• Además de los especificados por las constantes "cl"

• En Delphi, el tipo TColor especifica el color de un objeto. Es utilizado por la


propiedad Color de muchos componentes y por otras propiedades que
especifican valores de color.

• La unidad Graphics contiene definiciones de constantes útiles para TColor.


Por ejemplo, clBlue se asigna a mapas azules, clRed a rojo.

• Más valores "cl" = Más colores


• Puede especificar TColor como un número hexadecimal de 4 bytes en lugar
de usar las constantes definidas en la unidad de gráficos.
• Los tres bytes bajos representan intensidades de color RGB (rojo, verde,
azul) para azul, verde y rojo, respectivamente. Tenga en cuenta la inversión
de un color hexadecimal típico: para TColor, la secuencia es azul-verde-
roja.

• Por ejemplo, el rojo se puede definir como TColor ($ 0000FF).

• Convierte RBG a TColor


• Si tiene valores para las intensidades de rojo, verde y azul (un número de 0
a 255 - tipo de "byte"), aquí le mostramos cómo obtener el valor de TColor:

• > var r, g, b: Byte; color: TColor; begin r: = StrToInt (ledRed.Text); g: = StrToInt


(ledGreen.Text); b: = StrToInt (ledBlue.Text); color: = RGB (r, g, b); Shape1.Brush.Color:
= color; fin ;

• El "ledRed", "ledGreen" y "ledBlue" son tres controles de edición utilizados


para especificar la intensidad de cada componente de color. Shape1 es un
control TShape Delphi.

Vista de árbol virtual - Cómo instalar -


Delphi 3rd Party Open Source Component
• by Zarko Gajic

Vista de árbol virtual - Muestra en acción


Cualquier vista en árbol como componente es para mostrar una lista jerárquica de
elementos. Uno de los más comunes que usa y ve todos los días es el que se usa
en el Explorador de Windows: para mostrar carpetas (y más) en su sistema de
archivos.

Delphi viene con el control TTreeView, ubicado en la sección "Win32" de la paleta


de herramientas. Definido en la unidad ComCtrls, TTreeView realiza una tarea
decente que le permite presentar cualquier relación padre-hijo de cualquier tipo de
objetos.

Cada nodo en TTreeView consiste en una etiqueta y una imagen de mapa de bits
opcional, y el objeto TTreeNode describe un nodo individual en un control
TTreeView.

Si bien es lo suficientemente potente para la mayoría de las tareas si su aplicación


se basa en mostrar datos jerárquicos, como carpetas y archivos, estructura XML,
cualquier elemento similar, pronto se daría cuenta de que necesita más potencia
desde una vista en árbol como componente.
Aquí es donde una joya del mundo de componentes de terceros viene al rescate:
el componente TreeView virtual.

TreeView virtual

Virtual TreeView, que inicialmente estaba siendo desarrollado por Mike Lischke y
ahora se mantiene como un proyecto de código abierto en Google Code, es un
control de uso obligatorio si está dispuesto a trabajar con lo que pueda llamar
"nodos".

Con más de 13 años dedicados al desarrollo, Virtual TreeView es uno de los


componentes de código abierto más sofisticados, flexibles y avanzados para el
mercado Delphi.

No importa la versión de Delphi que esté utilizando, desde Delphi 7 hasta la última
versión (XE3 en este momento), podrá usar y aprovechar la potencia
de TVirtualStringTree y TVirtualDrawTree (los nombres reales de los controles)
en sus aplicaciones.

Estas son solo algunas de las características de "por qué usar" del control
TreeView virtual:

▪ muy pequeña huella de memoria.


▪ súper rápido.
▪ virtual, lo que significa que no sabe acerca de los datos que administra, solo el
tamaño. Todo se hace a través de eventos.
▪ admite vistas de múltiples columnas
▪ fácil personalización de una visualización de nodo con mapas de bits y estilos
de fuente.
▪ arrastrar y soltar el portapapeles
▪ cada nodo en el árbol puede tener su propio tipo de verificación (incluso
comprobación parcial mixta de tres estados).
▪ sofisticada serialización de contenido de árbol.
▪ edite datos de árbol usando editores definidos por la aplicación.
Con este artículo, estoy comenzando una serie de artículos de estilo sobre cómo
usar el control TVirtualStringTree.

Para empezar, veamos cómo instalar Virtual TreeView en el IDE de Delphi.

02 de 03
Virtual TreeView - Cómo instalar

TreeView virtual - Instalar en IDE


Primero, descargue el paquete principal TreeView virtual (en "Descargas").

Descargue un archivo ZIP que contiene el código fuente, paquetes para instalar el
componente en Delphi, algunas demostraciones y más.

Descomprime el contenido del archivo en alguna carpeta donde tengas otros


componentes de terceros. Estoy usando "C: \ Users \ Public \ Documents \
Delphi3rd \" y para mí la ubicación es "C: \ Users \ Public \ Documents \ Delphi3rd \
VirtualTreeviewV5.1.0"

A continuación, le mostramos cómo instalar Virtual TreeView en Delphi XE3 / RAD


Studio XE3

1. Abra el grupo de proyectos "Paquetes \ RAD Studio XE2 \ RAD Studio


XE3.groupproj".
2. Haga clic derecho en "VirtualTreesD16.bpl" y haga clic en "Instalar".
3. Vaya a "Herramientas> Opciones> Opciones de entorno> Opciones de Delphi>
Biblioteca> Ruta de biblioteca> [...]". Navegue a la carpeta "Fuente" de Virtual
TreeView, presione "OK", "Agregar", "OK", "OK"
4. Guarde el proyecto. Archivo - Cerrar todo.
Nota: si todavía usa Delphi 7, el paquete que necesita instalar se llama "Paquetes \
Delphi 7 \ VirtualTrees.bpg" para las versiones posteriores será "Paquetes \ Delphi
[versión] \ Delphi [versión] .groupproj" .
Una vez instalado, encontrará 3 componentes en la sección "Controles virtuales"
de la Paleta de herramientas:
▪ TVirtualStringTree - el control principal que usará - administra los subtítulos de
los nodos por sí mismo.
▪ TVirtualDrawTree: permite que la aplicación dibuje sus propios elementos en la
ventana del árbol.
▪ TVTHeaderPopupMenu: proporciona una forma conveniente de implementar
una ventana emergente de encabezado utilizada para cambiar la visibilidad de
las columnas.
03 de 03

Vista de árbol virtual - Ejemplo de "Hola mundo"

Virtual TreeView - Ejemplo de Hello


WorldUna vez que el paquete TreeView virtual esté instalado en Delphi / Rad
Studio IDE, ejecutemos el proyecto de muestra del paquete descargado para ver si
todo funciona :)
Cargue el proyecto ubicado en "\ Demos \ Minimal \", el nombre del proyecto es
"Minimal.dpr".

Correr.

Vea qué tan rápido es agregar cientos (incluso miles) de nodos como nodos
secundarios a uno seleccionado. Finalmente, aquí está el código fuente
(implementación importante) de este ejemplo de "mundo hello": >

>>> tipo de implementación PMyRec = ^ TMyRec; TMyRec = título de grabación :


WideString; fin ; procedure TMainForm.FormCreate (Sender:
TObject); comenzar VST.NodeDataSize: = SizeOf (TMyRec); VST.RootNodeCount: =
20; fin ; procedimiento TMainForm.ClearButtonClick (Sender: TObject); var Start:
Cardinal; begin Screen.Cursor: = crHourGlass; intente Start: =
GetTickCount; VST.Clear; Label1.Caption: = Format ('Duración de la última
operación:% d ms', [GetTickCount - Start]); finalmente Screen.Cursor: =
crDefault; fin ; fin ; procedimiento TMainForm.AddButtonClick (Sender:
TObject); var Count: Cardinal; Inicio: Cardenal; begin Screen.Cursor: =
crHourGlass; con VST intente Start: = GetTickCount; case (Sender as TButton) .Tag
de 0: // add to root begin Count: = StrToInt (Edit1.Text); RootNodeCount: =
RootNodeCount + Count; fin ; 1: // agregue como secundario si está asignado
(FocusedNode) y luego comience Count: = StrToInt (Edit1.Text); ChildCount
[FocusedNode]: = ChildCount [FocusedNode] + Count; Expandido [FocusedNode]: =
True; InvalidateToBottom (FocusedNode); fin ; fin; Label1.Caption: = Format
('Duración de la última operación:% d ms', [GetTickCount -
Start]); finalmente Screen.Cursor: =
crDefault; fin ; fin ; procedimiento TMainForm.VSTFreeNode (Remitente:
TBaseVirtualTree; Node: PVirtualNode); var Data: PMyRec; begin Data: =
Sender.GetNodeData (Node); Finalizar (Datos
^); fin ; procedimiento TMainForm.VSTGetText (Remitente: TBaseVirtualTree; Nodo:
PVirtualNode; Columna: TColumnIndex; TextType: TVSTTextType; var CellText:
string); var Data: PMyRec; begin Data: = Sender.GetNodeData (Node); si se asigna
(datos), entonces CellText: = Data.Caption; fin ; procedure TMainForm.VSTInitNode
(Remitente: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates:
TVirtualNodeInitStates); var Data: PMyRec; comience con
el Remitente do begin Data: = GetNodeData (Node); Data.Caption: = Formato
('Nivel% d, Índice% d', [GetNodeLevel (Node), Node.Index]); fin ; fin ; Por el
momento no entraré en detalles ... esto seguirá ...

Redimensionar proporcionalmente una


imagen: crear gráficos en miniatura
• by Zarko Gajic
• En la "programación" de gráficos, una miniatura es una versión de tamaño
reducido de una imagen.

• Aquí hay una idea para su próxima aplicación: crear un "selector de


formularios" para que los usuarios puedan seleccionar y navegar fácilmente
a través de formularios abiertos mostrando miniaturas de todos ellos en una
ventana de diálogo.

• ¿Idea interesante? Suena como la característica "Quick Tabs" del


navegador IE 7 :)

• Antes de crear realmente una función tan clara para su próxima aplicación
Delphi, debe saber cómo obtener la imagen del formulario ("captura de
pantalla de formulario") y cómo cambiar el tamaño proporcionalmente a la
imagen en miniatura deseada.

• Redimensionamiento de imagen proporcional: creación de gráficos en


miniatura
• A continuación encontrará un bloque de código para tomar la imagen de un
formulario (Form1) utilizando el método GetFormImage . El TBitmap
resultante se redimensiona para ajustarse al ancho máximo de miniatura
(200 píxeles) y / o alto (150 píxeles).
El cambio de tamaño mantiene la relación de aspecto de la imagen.

• La imagen resultante se muestra en un control de TI, llamado "Imagen1".

• > const maxWidth = 200; maxHeight = 150; var thumbnail: TBitmap; thumbRect:
TRect; comenzar miniatura: = Form1.GetFormImage; prueba thumbRect.Left: =
0; thumbRect.Top: = 0; // cambio de tamaño proporcional si thumbnail.Width>
thumbnail.Height luego comienza con thumbRect.Right: =
maxWidth; thumbRect.Bottom: = (maxWidth *
thumbnail.Height) div thumbnail.Width; end else begin thumbRect.Bottom: =
maxHeight; thumbRect.Right: = (maxHeight *
thumbnail.Width) div thumbnail.Height; fin ; thumbnail.Canvas.StretchDraw
(thumbRect, miniatura); // cambiar el tamaño de la miniatura de la imagen . Ancho:
= thumbRect.Right; thumbnail.Height: = thumbRect.Bottom; // mostrar en un control
de TImage Image1.Picture.Assign (thumbnail); finalmente miniatura. Libre; fin ; fin ;

• Nota: GetFormImage solo copia el área de cliente de formulario: si necesita


tomar toda la "captura de pantalla" de un formulario (incluido su borde),
necesitará un enfoque diferente ... más sobre él la próxima vez

Implementación en Item Click / Double


Click para TListView
• by Zarko Gajic

ListView.OnItemClick / OnItemDblClick
El control TListView de Delphi muestra una lista de elementos en columnas con
encabezados de columnas y subtemas, o vertical u horizontalmente, con iconos
pequeños o grandes.

Al igual que la mayoría de los controles Delphi, TListView expone los


eventos OnClick y OnDblClick (OnDoubleClick).

Desafortunadamente, si necesita saber en qué elemento se hizo clic o se hizo


doble clic, no puede simplemente manejar los eventos OnClick / OnDblClick para
obtener el elemento al que se hace clic.

El evento OnClick (OnDblClick) para TListView se activa cada vez que el usuario
hace clic en el control, es decir, cada vez que el "clic" ocurre en algún lugar dentro
del área del cliente del control .

El usuario puede hacer clic dentro de la vista de lista, PERO "perder" alguno de
los elementos. Además, dado que la vista de lista puede cambiar su visualización
dependiendo de la propiedad ViewStyle, el usuario podría haber hecho clic en un
elemento, en un título de elemento, en un icono de elemento, "en ninguna parte",
en un icono de estado de elemento, etc.

Nota: la propiedad ViewStyle determina cómo se muestran los elementos en la


vista de lista: los elementos se pueden mostrar como un conjunto de iconos
movibles o como columnas de texto.

ListView.On Item Click & ListView.On Item Double Click


Para poder ubicar el elemento cliqueado (si hay uno) cuando se activa el evento OnClick
para la vista de lista, debe determinar qué elementos de la vista de lista se encuentran bajo
el punto especificado por los parámetros X e Y, que es el ubicación del mouse en el
momento del "clic".

La función GetHitTestInfoAt de TListiew devuelve información sobre el punto


especificado en el área de cliente de la vista de lista.

Para asegurarse de que se hizo clic en el elemento (o se hizo doble clic), debe
llamar al GetHitTestInfoAt y reaccionar solo si el evento click se produjo en un
elemento real.

Aquí hay una implementación de ejemplo del evento OnDblClick de ListView1:

> // maneja el procedimiento de Click Double Click TForm de


ListView1. ListView1 DblClick (Sender: TObject); var hts: THitTests; ht:
THitTest; sht: cadena ; ListViewCursosPos: TPoint; selectedItem: TListItem; begin // posición
del cursor del mouse relacionado con ListView ListViewCursosPos: = ListView1.ScreenToClient
(Mouse.CursorPos); // haz doble clic donde? hts: = ListView1.GetHitTestInfoAt
(ListViewCursosPos.X, ListViewCursosPos.Y); // prueba de golpe "debug" Leyenda: =
''; para ht en hts do begin sht: = GetEnumName (TypeInfo (THitTest), Integer (ht)); Leyenda:
= Formato ('% s% s |', [Caption, sht]); fin ; // ubicar el elemento de doble clic si hts <=
[htOnIcon, htOnItem, htOnLabel, htOnStateIcon] luego comienza selectedItem: =
ListView1.Selected; // hacer algo con el elemento doble clic! Título: = Formato ('DblClcked:%
s', [selectedItem.Caption]); fin ; fin ;

En el controlador de eventos OnDblClick (o OnClick), lea la función


GetHitTestInfoAt al proporcionarle la ubicación del mouse "dentro" del control.
Para obtener la posición del mouse relacionada con la vista de lista, la función
ScreenToClient se usa para convertir un punto (mouse X e Y) en coordenadas de
pantalla en coordenadas locales, o del área del cliente.

GetHitTestInfoAt devuelve un valor del tipo THitTests . THitTests es un conjunto


de valores enumerados de THitTest .

Los valores de enumeración de THitTest, con su descripción, son:

▪ htAbove - sobre el área del cliente.


▪ htBelow : debajo del área del cliente.
▪ htNowhere - dentro del control, pero no en un elemento.
▪ htOnItem - en un elemento, su texto o su mapa de bits.
▪ htOnButton - en un botón.
▪ htOnIcon - en un icono.
▪ htOnIndent : en el área sangrada de un elemento.
▪ htOnLabel - en una etiqueta.
▪ htOnRight - en el lado derecho de un artículo.
▪ htOnStateIcon : en un icono de estado o mapa de bits asociado a un elemento.
▪ htToLeft : a la izquierda del área del cliente.
▪ htToRight - a la derecha del área del cliente.
Si el resultado de la llamada a GetHitTestInfoAt es un subconjunto (establece
Delphi!) De [htOnIcon, htOnItem, htOnLabel, htOnStateIcon], puede estar seguro
de que el usuario hizo clic en el elemento (o en su ícono de icono / estado).

Finalmente, si lo anterior es verdadero, lea la propiedad Seleccionado de la vista


de lista, devuelve el primer elemento seleccionado (si se puede seleccionar el
número múltiple) en la vista de lista.

Haga algo con el elemento cliqueado / doble clic / seleccionado ...

Asegúrese de descargar el código fuente completo para explorar el código y


aprender al adoptarlo :)
Crear una pantalla de bienvenida en
aplicaciones Delphi
• by Zarko Gajic

Construya una pantalla de bienvenida de Delphi para indicar el proceso de carga

La pantalla de bienvenida más básica es solo una imagen, o más precisamente,


un formulario con una imagen , que aparece en el centro de la pantalla cuando la
aplicación se está cargando. Las pantallas de bienvenida están ocultas cuando la
aplicación está lista para ser utilizada.

A continuación hay más información sobre los diferentes tipos de pantallas de


presentación que puede ver y por qué son útiles, así como los pasos para crear su
propia pantalla de presentación de Delphi para su aplicación.

¿Para qué se utilizan las pantallas Splash?

Hay varios tipos de pantallas de presentación. Las más comunes son las pantallas
de inicio, las que ves cuando una aplicación se está cargando. Por lo general,
muestran el nombre, autor, versión, derechos de autor e imagen de la aplicación, o
algún tipo de ícono, que lo identifica de manera única.

Si es un desarrollador de shareware, puede usar pantallas de bienvenida para


recordarle a los usuarios que deben registrar el programa. Estos pueden aparecer
cuando el programa se inicia por primera vez, para decirle al usuario que pueden
registrarse si desean funciones especiales o recibir actualizaciones por correo
electrónico para las nuevas versiones.

Algunas aplicaciones usan pantallas de presentación para notificar al usuario del


progreso de un proceso que consume mucho tiempo. Si observa detenidamente,
algunos programas realmente grandes utilizan este tipo de pantalla de bienvenida
cuando el programa carga procesos en segundo plano y dependencias. Lo último
que desea es que sus usuarios piensen que su programa está "muerto" si se está
realizando alguna tarea en la base de datos.

Crear una pantalla de bienvenida

Veamos cómo crear una pantalla de bienvenida de inicio simple en unos pocos
pasos:

1. Agregue un nuevo formulario a su proyecto.

Seleccione Nuevo formulario en el menú Archivo en Delphi IDE.


2. Cambie la propiedad de nombre del formulario a algo como SplashScreen .
3. Cambie estas Propiedades: BorderStyle a bsNone , Position a poScreenCenter .

1. Personalice su pantalla de bienvenida agregando componentes como etiquetas,


imágenes, paneles, etc.

Primero puede agregar un componente TPanel ( Align: alClient ) y jugar con


las propiedades
BevelInner , BevelOuter , BevelWidth , BorderStyle y BorderWidth para producir
algunos efectos llamativos .
2. Seleccione Proyecto en el menú Opciones y mueva el Formulario desde el
cuadro de lista Crear automáticamente a Formularios disponibles .

Crearemos un formulario sobre la marcha y luego lo mostraremos antes de que


la aplicación se abra realmente.
3. Seleccione Fuente del proyecto en el menú Ver .

También puede hacer esto a través de Proyecto> Ver fuente .


4. Agregue el siguiente código después de la instrucción begin del código fuente
del proyecto (el archivo .DPR): > Application.Initialize; // esta linea
existe! SplashScreen: = TSplashScreen.Create
(nil); SplashScreen.Show; SplashScreen.Update;
5. Después de la última Application.Create () y antes de la
instrucción Application.Run , agregue: > SplashScreen.Hide; SplashScreen.Free;
6. ¡Eso es! Ahora puedes ejecutar la aplicación.

En este ejemplo, dependiendo de la velocidad de su computadora, apenas verá su


nueva pantalla de bienvenida, pero si tiene más de un formulario en su proyecto,
la pantalla de presentación aparecerá.

Para obtener más información sobre cómo hacer que la pantalla de bienvenida
permanezca un poco más, lea el código en este subproceso de desbordamiento
de pila.

Consejo: también puede crear formularios Delphi personalizados.

Cómo crear, usar y cerrar formularios en


Delphi
• by Zarko Gajic

Comprender el ciclo de vida de un formulario de Delphi

En Windows, la mayoría de los elementos de la interfaz de usuario son ventanas.


En Delphi , cada proyecto tiene al menos una ventana: la ventana principal del
programa. Todas las ventanas de una aplicación Delphi se basan en objetos
TForm.

Formar
Los objetos de formulario son los componentes básicos de una aplicación Delphi,
las ventanas reales con las que un usuario interactúa cuando ejecuta la aplicación.
Los formularios tienen sus propias propiedades, eventos y métodos con los que
puede controlar su apariencia y comportamiento.

Un formulario es en realidad un componente Delphi, pero a diferencia de otros


componentes, un formulario no aparece en la paleta de componentes.

Normalmente creamos un objeto de formulario iniciando una nueva aplicación


(Archivo | Nueva Aplicación). Esta forma recién creada será, por defecto, la forma
principal de la aplicación, la primera forma creada en tiempo de ejecución.

Nota: Para agregar un formulario adicional al proyecto Delphi, seleccionamos


Archivo | Nuevo formulario. Hay, por supuesto, otras formas de agregar un
formulario "nuevo" a un proyecto Delphi.

Nacimiento
OnCreate
El evento OnCreate se activa cuando se crea un TForm por primera vez, es decir,
solo una vez. La declaración responsable de crear el formulario está en el origen
del proyecto (si el proyecto lo configura automáticamente). Cuando se está
creando un formulario y su propiedad Visible es Verdadero, los siguientes eventos
ocurren en el orden indicado: OnCreate, OnShow, OnActivate, OnPaint.

Debe usar el controlador de eventos OnCreate para hacer, por ejemplo, tareas de
inicialización como la asignación de listas de cadenas.

Cualquier objeto creado en el evento OnCreate debe ser liberado por el evento
OnDestroy.

> OnCreate -> OnShow -> OnActivate -> OnPaint -> OnResize -> OnPaint ...

En el programa
Este evento indica que se está mostrando el formulario. Se llama a OnShow justo
antes de que un formulario sea visible. Además de las formas principales, este
evento ocurre cuando establecemos la propiedad Visible de los formularios en
True, o llamamos al método Show o ShowModal.
Activado
Se llama a este evento cuando el programa activa el formulario, es decir, cuando
el formulario recibe el foco de entrada. Use este evento para cambiar qué control
realmente obtiene el foco si no es el deseado.

OnPaint, OnResize
Eventos como OnPaint y OnResize siempre se llaman después de que se crea el
formulario inicialmente, pero también se llaman repetidamente. OnPaint ocurre
antes de que se pinten los controles del formulario (úselo para una pintura
especial en el formulario).

Vida
Como hemos visto, el nacimiento de una forma no es tan interesante como
pueden ser la vida y la muerte. Cuando se crea su formulario y todos los controles
están esperando que los eventos lo manejen, ¡el programa se ejecuta hasta que
alguien intente cerrar el formulario!

Muerte
Una aplicación controlada por eventos deja de ejecutarse cuando todas sus
formas están cerradas y no se está ejecutando ningún código. Si aún existe un
formulario oculto cuando se cierra el último formulario visible, parecerá que su
aplicación ha finalizado (porque no hay formularios visibles), pero de hecho
continuará ejecutándose hasta que se cierren todos los formularios ocultos. Solo
piense en una situación donde la forma principal se oculta temprano y todas las
otras formas están cerradas.

> ... OnCloseQuery -> OnClose -> OnDeactivate -> OnHide -> OnDestroy

OnCloseQuery
Cuando tratamos de cerrar el formulario usando el método Close o por otros
medios (Alt + F4), se llama al evento OnCloseQuery.

Por lo tanto, el controlador de eventos para este evento es el lugar para interceptar
el cierre de un formulario y evitarlo. Usamos OnCloseQuery para preguntar a los
usuarios si están seguros de que realmente desean que el formulario se cierre.

> procedure TForm1.FormCloseQuery (Sender: TObject; var CanClose:


Boolean); comience si MessageDlg ('¿Cerrar realmente esta ventana?', mtConfirmation,
[mbOk, mbCancel], 0) = mrCancel luego CanClose: = False; fin ;

Un controlador de eventos OnCloseQuery contiene una variable CanClose que


determina si un formulario puede cerrarse. El controlador de eventos
OnCloseQuery puede establecer el valor de CloseQuery en False (a través del
parámetro CanClose), anulando así el método Close.
OnClose
Si OnCloseQuery indica que el formulario debe cerrarse, se llama al evento
OnClose.

El evento OnClose nos da una última oportunidad para evitar que se cierre el
formulario.

El controlador de eventos OnClose tiene un parámetro de acción, con los


siguientes cuatro valores posibles:

▪ caNone . El formulario no puede cerrarse. Como si hubiéramos configurado CanClose


en False en OnCloseQuery.
▪ caHide . En lugar de cerrar el formulario, lo ocultas.
▪ caFree . El formulario está cerrado, por lo que Delphi libera la memoria asignada.
▪ caminizar La forma es minimizada, en lugar de cerrada. Esta es la acción
predeterminada para formularios secundarios MDI. Nota: Cuando un usuario apaga
Windows, el evento OnCloseQuery se activa, no OnClose. Si desea evitar que Windows
se cierre, coloque su código en el controlador de eventos OnCloseQuery, por supuesto
CanClose = False no servirá.
OnDestroy
Después de que se haya procesado el método OnClose y se cierre el formulario,
se llama al evento OnDestroy. Utilice este evento para operaciones opuestas a las
del evento OnCreate. Por lo tanto, OnDestroy se usa para desasignar objetos
relacionados con el formulario y liberar la memoria correspondiente.

Por supuesto, cuando se cierra el formulario principal para un proyecto, la


aplicación finaliza.

Cómo cambiar el color en el componente


TDBGrid
• by Zarko Gajic
• Agregar color a las cuadrículas de la base de datos mejorará la apariencia y
diferenciará la importancia de ciertas filas o columnas dentro de la base de
datos. Haremos esto centrándonos en DBGrid , que proporciona una
excelente herramienta de interfaz de usuario para mostrar datos.

• Supondremos que ya sabe cómo conectar una base de datos a un


componente DBGrid. La forma más sencilla de lograr esto es usar el
Asistente de formularios de base de datos. Seleccione employee.db del
alias DBDemos y seleccione todos los campos excepto EmpNo .
• Columnas para colorear
• Lo primero y más fácil que puede hacer para mejorar visualmente la interfaz
de usuario es colorear columnas individuales en la cuadrícula de datos. Lo
lograremos a través de la propiedad TColumns de la grilla.

• Seleccione el componente de cuadrícula en el formulario e invoque el editor


Columnas haciendo doble clic en la propiedad Columnas de la cuadrícula
en el Inspector de Objetos.

• Lo único que queda por hacer es especificar el color de fondo de las celdas
para cualquier columna en particular. Para el color de primer plano de texto,
vea la propiedad de la fuente.

• Consejo: para obtener más información sobre el editor Columns, busque


el editor Columns: crear columnas persistentes en sus archivos de ayuda
de Delphi .

• Filas para colorear


• Si desea colorear la fila seleccionada en un DBGrid pero no desea usar la
opción dgRowSelect (porque desea poder editar los datos), en su lugar
debe usar el evento DBGrid.OnDrawColumnCell.

• Esta técnica demuestra cómo cambiar dinámicamente el color del texto en


un DBGrid:

• procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect;


DataCol: Entero; Columna: TColumn; Estado:
TGridDrawState); comience si Table1.FieldByName ('Salary'). AsCurrency>
36000 then DBGrid1.Canvas.Font.Color: = clMaroon;
DBGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State); fin ;

• Aquí se muestra cómo cambiar dinámicamente el color de una fila en un


DBGrid:

• procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect;


DataCol: Entero; Columna: TColumn; Estado:
TGridDrawState); comience si Table1.FieldByName ('Salary'). AsCurrency>
36000 then DBGrid1.Canvas.Brush.Color: = clWhite;
DBGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State); fin ;

• Células para colorear


• Finalmente, he aquí cómo cambiar el color de fondo de las celdas de
cualquier columna en particular, más el color de primer plano del texto:

• procedure TForm1.DBGrid1DrawColumnCell (Sender: TObject; const Rect: TRect;


DataCol: Entero; Columna: TColumn; Estado:
TGridDrawState); comience si Table1.FieldByName ('Salary'). AsCurrency>
40000 entonces comience DBGrid1.Canvas.Font.Color: = clWhite;
DBGrid1.Canvas.Brush.Color: = clBlack; fin ; si DataCol = 4, entonces // 4 ° columna
es 'Salario' DBGrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State); fin ;

• Como puede ver, si el salario de un empleado es superior a 40 mil, su celda


de salario se muestra en negro y el texto se muestra en blanco.

Cómo implementar el evento OnCreate


para un objeto Delphi TFrame
• by Zarko Gajic
• Agregar TFrame.OnCreate

• TFrame es un contenedor para componentes; se puede anidar dentro de


formularios u otros marcos.

• Un marco, como una forma, es un contenedor para otros componentes. Los


marcos se pueden anidar en formularios u otros marcos, y se pueden
guardar en la paleta de componentes para facilitar su reutilización.

• ¡Faltando a OnCreate!
• Una vez que comience a usar marcos, notará que no hay ningún
evento OnCreate que pueda usar para inicializar sus marcos.

• En resumen, la razón por la que un marco no tiene un evento OnCreate es


que no hay un buen momento para disparar el evento.

• Sin embargo, anulando el método Create puede imitar el evento


OnCreate. Después de todo, OnCreate for Forms se activa al final del
Create constructor, por lo que anular Create for Frames es tener el evento
OnCreate.

• Aquí está el código fuente de un marco simple que expone una propiedad
pública y anula el constructor Crear:

• > unidad WebNavigatorUnit; la interfaz usa Windows, Mensajes, SysUtils,


Variantes, Clases, Gráficos, Controles, Formularios, Diálogos,
StdCtrls; tipo TWebNavigatorFrame = class (TFrame) urlEdit:
TEdit; fURL privado : cadena ; procedimiento SetURL (valor
de const : cadena ); public constructor Create (AOwner:
TComponent); anular ; URL de la propiedad publicada : string
read fURL write SetURL; fin ; implementación {$ R *
.dfm} constructor TWebNavigatorFrame.Create (AOwner:
TComponent); comenzar heredado Create (AOwner); // URL del código "OnCreate" :
= 'http://delphi.about.com'; fin ; procedimiento TWebNavigatorFrame.SetURL
( const Value: string ); comenzar fURL: = Valor; urlEdit.Text: = Valor; fin ; fin

• El "WebNavigatorFrame" actúa como un iniciador de sitio web que aloja una


edición y un botón de control. Nota: si es nuevo en los marcos, asegúrese
de leer los dos artículos siguientes: desarrollo de componente virtual
utilizando marcos, hojas de herramientas de desplazamiento con marcos

Depuración frente a versión en


configuraciones de compilación Delphi
• by Zarko Gajic

01 de 03

Configuraciones de compilación - Base: Depurar, liberar

Delphi Project Manager. Zarko


Gajic
La ventana Project Manager en su IDE de Delphi (RAD Studio) muestra y organiza
los contenidos de su grupo de proyectos actual y cualquier proyecto que contenga.
Enumerará todas las unidades que forman parte de su proyecto, así como todas
las formas y archivos de recursos incluidos.

La sección Configuraciones de compilación mostrará una lista de varias


configuraciones de compilación que tiene para su proyecto.

Algunos más recientes (para ser correctos: a partir de Delphi 2007 ) Las versiones
de Delphi tienen dos (tres) configuraciones predeterminadas de compilación:
DEPURACIÓN y LIBERACIÓN.
El artículo de Compilación condicional 101 menciona configuraciones de
compilación, pero no explica la diferencia en los detalles.

Depurar frente a versión

Como puede activar cada una de las configuraciones de compilación que ve en el


Administrador de proyectos y crear su proyecto produciendo un archivo ejecutable
diferente, la pregunta es: ¿cuál es la diferencia entre Depurar y Liberar?

La denominación en sí misma: "depuración" y "liberación" debe apuntar en la


dirección correcta.

▪ La configuración de depuración debe estar activa y utilizada mientras


desarrollamos y depuramos y cambiamos su aplicación.
▪ La configuración de liberación debe activarse cuando construimos su aplicación
para que el archivo ejecutable producido se envíe a los usuarios.
Sin embargo, la pregunta sigue siendo: ¿cuál es la diferencia? ¿Qué se puede
hacer mientras "depurar" está activo y qué se incluye en el archivo ejecutable final
frente a cómo se ve el ejecutable cuando se aplica "release"?

Configuraciones de compilación

De forma predeterminada, hay tres (aunque en el Administrador de proyectos solo


se ven dos) configuraciones de compilación creadas por Delphi cuando se inicia
un nuevo proyecto . Esos son Base, Debug y Release.

La configuración base actúa como un conjunto básico de valores de opción que


se utiliza en todas las configuraciones que posteriormente crea.

Los valores de opción mencionados son la compilación y el enlace, y otro


conjunto de opciones que puede modificar para su proyecto utilizando el cuadro de
diálogo Opciones de proyecto (menú principal: Proyecto - Opciones).

La configuración de depuración extiende Base desactivando la optimización y


habilitando la depuración, además de establecer opciones de sintaxis específicas.

La configuración Release extiende Base para no producir información de


depuración simbólica, el código no se genera para llamadas TRACE y ASSERT, lo
que significa que el tamaño de su ejecutable se reduce.

Puede agregar sus propias configuraciones de compilación y puede eliminar las


configuraciones predeterminadas de depuración y liberación, pero no puede
eliminar la base.
Las configuraciones de compilación se guardan en el archivo de proyecto (.dproj).
El DPROJ es un archivo XML, así es como la sección con configuraciones de
compilación:

> 00400000. \ $ (Config) \ $ (Plataforma) WinTypes = Windows; WinProcs =


Windows; DbiTypes = BDE; DbiProcs = BDE; $ (DCC_UnitAlias). \ $ (Config) \ $
(Plataforma) DEBUG; $ (DCC_Define) falso verdadero falso lanzamiento; $
(DCC_Define) 0 falso
Por supuesto, no alterará el archivo DPROJ manualmente, sino que Delphi lo
mantendrá.

* Puedes * cambiar el nombre de configuraciones de compilación, * puedes *


modificar las configuraciones para cada configuración de compilación, * puedes *
hacer que "liberación" sea para la depuración y "depuración" se optimice para tus
clientes. Por lo tanto, no necesitas saber lo que estás haciendo :)

Compilar, construir, correr

Mientras está trabajando en su aplicación, desarrollándola, puede compilar,


compilar y ejecutar la aplicación directamente desde el IDE. Compilar, construir y
ejecutar producirá el archivo ejecutable.

La sintaxis de compilación verificará su código y compilará la aplicación, teniendo


en cuenta solo aquellos archivos que han cambiado desde la última compilación.
La compilación produce archivos DCU.

Construir es una extensión para compilar donde se compilan todas las unidades
(incluso aquellas que no están alteradas). Cuando cambias las opciones del
proyecto, ¡debes construir!

Running compila el código y ejecuta la aplicación. Puede ejecutar la depuración


(F9) o sin depuración (Ctrl + Shift + F9). Si se ejecuta sin depurar, el depurador
integrado en el IDE no se invocará; sus puntos de corte de depuración "no"
funcionarán.

Ahora que sabe cómo y dónde se guardan las configuraciones de compilación,


veamos la diferencia entre las compilaciones Debug y Release.

02 de 03

Configuración de compilación: DEPURACIÓN - para depuración y


desarrollo
Configuración de
compilación de depuración en Delphi. Zarko Gajic
La configuración predeterminada de compilación Debug, que puede ubicar en el
Administrador de proyectos para su proyecto Delphi, la crea Delphi cuando creó
una nueva aplicación / proyecto .

La configuración de depuración deshabilita la optimización y habilita la depuración.

Para editar la configuración de compilación: haga clic con el botón derecho en el


nombre de la configuración, seleccione "Editar" en el menú contextual y se
encontrará mirando el cuadro de diálogo Opciones del proyecto.

Opciones de depuración

Como la depuración extiende la compilación de la configuración base, las


configuraciones que tienen un valor diferente se mostrarán en negrita.

Para la depuración (y por lo tanto la depuración) las opciones específicas son:

▪ Compilador Delphi - Compilación - Generación de código - Optimización


DESACTIVADA - el compilador NO realizará una cantidad de optimizaciones de
código, como colocar variables en registros de CPU, eliminar subexpresiones
comunes y generar variables de inducción.
▪ Delphi Compiler - Compilación - Generación de código - Stack Frames ON -
los marcos de pila siempre se generan para procedimientos y funciones, incluso
cuando no son necesarios.
▪ Compilador Delphi - Compilación - Depuración - Información de depuración
ENCENDIDA - cuando un programa o unidad se compila con esta opción
habilitada, el depurador integrado le permite un solo paso y establecer
puntos de interrupción . La información de depuración que está "activada" no
afecta el tamaño o la velocidad del programa ejecutable; la información de
depuración se compila en las DCU y no se vincula al ejecutable.
▪ Compilador Delphi - Compilación - Depuración - Símbolos locales activados -
Cuando un programa o unidad se compila con esta opción habilitada,
el depurador integrado le permite examinar y modificar las variables
locales del módulo . Los símbolos locales que están "encendidos" no afectan el
tamaño o la velocidad del programa ejecutable.
NOTA: de forma predeterminada, la opción "use debug .dcus" está desactivada.
Establecer esta opción le permite depurar el código fuente de Delphi VCL
(establecer un punto de interrupción en el VCL)

Veamos de qué se trata la "Liberación" ...

03 de 03

Configuración de compilación: LIBERACIÓN - para distribución pública


Delphi Release Build
Configuration. Zarko Gajic
La versión predeterminada de la configuración de compilación, que puede ubicar
en el Administrador de proyectos para su proyecto Delphi, la crea Delphi cuando
creó una nueva aplicación / proyecto.

La configuración de lanzamiento permite la optimización y desactiva la depuración,


el código no se genera para llamadas TRACE y ASSERT, lo que significa que el
tamaño de su ejecutable se reduce.

Para editar la configuración de compilación: haga clic con el botón derecho en el


nombre de la configuración, seleccione "Editar" en el menú contextual y se
encontrará mirando el cuadro de diálogo Opciones del proyecto.

Opciones de lanzamiento

Dado que la versión amplía la configuración de la base, aquellas configuraciones


que tienen un valor diferente se mostrarán en negrita.

Para Release (la versión que usarán los usuarios de su aplicación, no para la
depuración), las opciones específicas son:

▪ Delphi Compiler - Compilación - Generación de código - Optimización


activada - el compilador realizará una serie de optimizaciones de código, como
colocar variables en registros de CPU, eliminar subexpresiones comunes y
generar variables de inducción.
▪ Delphi Compiler - Compilación - Generación de código - Stack Frames OFF -
los marcos de pila NO se generan para procedimientos y funciones.
▪ Compilador Delphi - Compilación - Depuración - Información de depuración
DESACTIVADA - cuando un programa o unidad se compila con esta opción
deshabilitada, el depurador integrado NO le permite un solo paso ni
establece puntos de interrupción .
▪ Compilador Delphi - Compilación - Depuración - Símbolos locales
DESACTIVADOS - Cuando un programa o unidad se compila con esta opción
deshabilitada, el depurador integrado NO le permite examinar y modificar
las variables locales del módulo .
Esos son los valores predeterminados establecidos por Delphi para un nuevo
proyecto. Puede modificar cualquiera de las opciones del Proyecto para crear su
propia versión de depuración o liberar configuraciones de compilación.

Operaciones Básicas del Portapapeles


(Cortar / Copiar / Pegar)
• by Zarko Gajic

Usar el objeto TClipboard

El Portapapeles de Windows representa el contenedor de cualquier texto o gráfico


que se corte, copie o pegue desde o hacia una aplicación. Este artículo le
mostrará cómo utilizar el objeto TClipboard para implementar funciones de cortar,
copiar y pegar en su aplicación Delphi.

Portapapeles en General
Como probablemente sepa, el Portapapeles solo puede contener una pieza de
datos para cortar, copiar y pegar al mismo tiempo. En general, puede contener
solo una parte del mismo tipo de datos a la vez.

Si enviamos nueva información del mismo formato al Portapapeles, borramos lo


que había antes. El contenido del Portapapeles permanece en el Portapapeles
incluso después de que pegamos esos contenidos en otro programa.

TClipboard
Para utilizar el Portapapeles de Windows en nuestras aplicaciones, debemos
agregar la unidad ClipBrd a la cláusula uses del proyecto, excepto cuando
restringimos cortar, copiar y pegar a los componentes que tienen soporte
incorporado para los métodos del Portapapeles. Esos componentes son TEdit,
TMemo, TOLEContainer, TDDEServerItem, TDBEdit, TDBImage y TDBMemo.
La unidad ClipBrd crea automáticamente una instancia de un objeto TClipboard
llamado Portapapeles. Utilizaremos los métodos
CutToClipboard , CopyToClipboard , PasteFromClipboard , Clear y HasFormat par
a manejar las operaciones del portapapeles y la manipulación de texto / gráficos.

Enviar y recuperar texto


Para enviar texto al Portapapeles, se usa la propiedad AsText del objeto
Portapapeles.

Si queremos, por ejemplo, enviar la información de cadena contenida en la


variable SomeStringData al Portapapeles (borrando cualquier texto que haya),
utilizaremos el siguiente código:

> usa ClipBrd; ... Clipboard.AsText: = SomeStringData_Variable;

Para recuperar la información de texto del Portapapeles usaremos

> usa ClipBrd; ... SomeStringData_Variable: = Clipboard.AsText;

Nota: si solo queremos copiar el texto de, digamos, Editar componente al


Portapapeles, no tenemos que incluir la unidad ClipBrd en la cláusula uses. El
método CopyToClipboard de TEdit copia el texto seleccionado en el control de
edición en el Portapapeles en el formato CF_TEXT.

> procedure TForm1.Button2Click (Sender: TObject); begin // la siguiente línea seleccionará


// TODO el texto en el control de edición {Edit1.SelectAll;} Edit1.CopyToClipboard; fin ;

Imágenes del Portapapeles


Para recuperar imágenes gráficas del Portapapeles, Delphi debe saber qué tipo de
imagen se almacena allí. Del mismo modo, para transferir imágenes al
portapapeles, la aplicación debe decirle al Portapapeles qué tipo de gráficos está
enviando. Algunos de los valores posibles del parámetro Formato siguen; hay
muchos más formatos de Portapapeles proporcionados por Windows.

▪ CF_TEXT - Texto con cada línea que termina con una combinación CR-LF .
▪ CF_BITMAP : un gráfico de mapa de bits de Windows.
▪ CF_METAFILEPICT : un metarchivo de Windows gráfico.
▪ CF_PICTURE - Un objeto de tipo TPicture.
▪ CF_OBJECT - Cualquier objeto persistente.
El método HasFormat devuelve True si la imagen en el Portapapeles tiene el
formato correcto:
> si Clipboard.HasFormat (CF_METAFILEPICT) a continuación, ShowMessage ('Portapapeles
tiene metarchivo');

Para enviar (asignar) una imagen al Portapapeles, usamos el método Asignar. Por
ejemplo, el siguiente código copia el mapa de bits de un objeto de mapa de bits
llamado MyBitmap en el Portapapeles:

> Clipboard.Assign (MyBitmap);

En general, MyBitmap es un objeto de tipo TGraphics, TBitmap, TMetafile o


TPicture.

Para recuperar una imagen del Portapapeles debemos: verificar el formato de los
contenidos actuales del portapapeles y usar el método Asignar del objeto de
destino:

> {coloque un botón y un control de imagen en form1} {Antes de ejecutar este código,
presione Alt-PrintScreen key
combination} usa clipbrd; ... procedimiento TForm1.Button1Click (Sender:
TObject); comenzar si Clipboard.HasFormat
(CF_BITMAP) luego Image1.Picture.Bitmap.Assign (Portapapeles); fin;

Más control del portapapeles


El portapapeles almacena información en múltiples formatos para que podamos
transferir datos entre aplicaciones que usan formatos diferentes.

Al leer información del portapapeles con la clase TClipboard de Delphi, estamos


limitados a los formatos de portapapeles estándar: texto, imágenes y metarchivos.

Supongamos que tenemos dos aplicaciones Delphi en ejecución, ¿qué opina


sobre la definición de un formato de portapapeles personalizado para enviar y
recibir datos entre esos dos programas? Supongamos que estamos intentando
codificar un elemento de menú Pegar: queremos que se deshabilite cuando no
haya, digamos, texto en el portapapeles. Dado que todo el proceso con el
portapapeles se lleva a cabo detrás de las escenas, no hay ningún método de la
clase TClipboard que nos informe que ha habido algún cambio en el contenido del
portapapeles. Lo que necesitamos es conectar el sistema de notificación del
portapapeles, para que podamos obtener y responder a los eventos cuando
cambie el portapapeles.

Si queremos más flexibilidad y funcionalidad, tenemos que ocuparnos de las


notificaciones de cambio de portapapeles y de los formatos de portapapeles
personalizados: escuchar en el portapapeles.
Ejecutar aplicaciones Delphi con
parámetros
• by Zarko Gajic
• Cómo pasar los parámetros de la línea de comando a su aplicación

• Aunque era mucho más común en la época de DOS, los sistemas


operativos modernos también le permiten ejecutar parámetros de línea de
comando en una aplicación para que pueda especificar qué debe hacer la
aplicación.

• Lo mismo es cierto para su aplicación Delphi, ya sea para una aplicación de


consola o una con una GUI. Puede pasar un parámetro desde Símbolo del
sistema en Windows o desde el entorno de desarrollo en Delphi, en la
opción de menú Ejecutar> Parámetros .

• Para este tutorial, usaremos el cuadro de diálogo de parámetros para pasar


argumentos de línea de comando a una aplicación para que sea como si lo
estuviéramos ejecutando desde el Explorador de Windows.

• ParamCount y ParamStr ()
• La función ParamCount devuelve el número de parámetros pasados al
programa en la línea de comando, y ParamStr devuelve un parámetro
especificado de la línea de comando.

• El controlador de eventos OnActivate del formulario principal suele ser


donde los parámetros están disponibles. Cuando la aplicación se está
ejecutando, está ahí para que puedan ser recuperados.

• Tenga en cuenta que en un programa, la variable CmdLine contiene una


cadena con argumentos de línea de comandos especificados cuando se
inició la aplicación. Puede usar CmdLine para acceder a la cadena de
parámetros completa pasada a una aplicación.

• Solicitud de muestra

• Inicie un nuevo proyecto y coloque un componente Button en el formulario .


En el controlador de eventos OnClick del botón, escriba el siguiente código:

• > procedure TForm1.Button1Click (Sender: TObject); comenzar ShowMessage


(ParamStr (0)); fin ;

• Cuando ejecuta el programa y hace clic en el botón, aparece un cuadro de


mensaje con la ruta y el nombre del archivo del programa en ejecución.
Puedes ver que ParamStr "funciona" incluso si no has pasado ningún
parámetro a la aplicación; esto se debe a que el valor de matriz 0 almacena
el nombre de archivo de la aplicación ejecutable, incluida la información de
ruta.

• Elija Parámetros del menú Ejecutar y luego agregue Programación Delphi a


la lista desplegable.

• Nota: Recuerde que cuando pasa parámetros a su aplicación, sepárelos


con espacios o pestañas. Use comillas dobles para ajustar varias palabras
como un parámetro, como cuando se utilizan nombres de archivos largos
que contienen espacios.

• El siguiente paso es recorrer los parámetros usando ParamCount () para


obtener el valor de los parámetros usando ParamStr (i) .

• Cambie el controlador de eventos OnClick del botón a este:

• > procedure TForm1.Button1Click (Sender: TObject); var j: entero; begin for j: =


1 to ParamCount do ShowMessage (ParamStr (j)); fin ;

• Cuando ejecuta el programa y hace clic en el botón, aparece un mensaje


que dice "Delphi" (primer parámetro) y "Programación" (segundo
parámetro).

Comprender el proyecto Delphi y los


archivos fuente de la unidad
• by Zarko Gajic
• Una explicación de los formatos .DPR y .PAS de Delphi

• En resumen, un proyecto Delphi es solo una colección de archivos que


componen una aplicación creada por Delphi. DPR es la extensión de
archivo utilizada para el formato de archivo Delphi Project para almacenar
todos los archivos relacionados con el proyecto. Esto incluye otros tipos de
archivos Delphi como archivos de formulario (DFM) y archivos de origen de
unidad (.PAS).

• Dado que es bastante común que las aplicaciones Delphi compartan código
o formularios previamente personalizados, Delphi organiza las aplicaciones
en estos archivos de proyecto.

• El proyecto se compone de la interfaz visual junto con el código que activa


la interfaz.

• Cada proyecto puede tener múltiples formularios que le permiten crear


aplicaciones que tienen múltiples ventanas. El código que se necesita para
un formulario se almacena en el archivo DFM, que también puede contener
información general del código fuente que puede ser compartida por todos
los formularios de la aplicación.

• Un proyecto Delphi no se puede compilar a menos que se use un archivo


de recursos de Windows (RES), que contiene el icono del programa y la
información de la versión. También podría contener otros recursos, como
imágenes, tablas, cursores, etc. Los archivos RES son generados
automáticamente por Delphi.

• Nota: Los archivos que terminan en la extensión de archivo DPR también


son archivos de Digital InterPlot utilizados por el programa Bentley Digital
InterPlot, pero no tienen nada que ver con los proyectos de Delphi.

• Más información sobre archivos DPR


• El archivo DPR contiene directorios para compilar una aplicación.
Normalmente, este es un conjunto de rutinas simples que abren el
formulario principal y cualquier otra forma que se configure para abrirse
automáticamente.

• A continuación, inicia el programa llamando a los


métodos Initialize , CreateForm y Run del objeto Application global.

• La aplicación de variable global, de tipo TApplication, está en cada


aplicación Delphi Windows. La aplicación encapsula su programa y
proporciona muchas funciones que ocurren en el fondo del software.

• Por ejemplo, la Aplicación maneja cómo llamarías a un archivo de ayuda


desde el menú de tu programa.

• DPROJ es otro formato de archivo para los archivos del Proyecto Delphi,
pero almacena la configuración del proyecto en formato XML.

• Más información sobre archivos PAS


• El formato de archivo PAS está reservado para los archivos fuente de la
unidad Delphi. Puede ver el código fuente del proyecto actual a través del
menú Proyecto> Ver fuente .

• Aunque puede leer y editar el archivo del proyecto como lo haría con
cualquier código fuente, en la mayoría de los casos, permitirá que Delphi
mantenga el archivo DPR. La razón principal para ver el archivo del
proyecto es ver las unidades y formularios que componen el proyecto, así
como para ver qué formulario se especifica como el formulario "principal" de
la aplicación.

• Otra razón para trabajar con el archivo de proyecto es cuando está creando
un archivo DLL en lugar de una aplicación independiente. O bien, si
necesita algún código de inicio, como una pantalla de bienvenida antes de
que Delphi cree el formulario principal.

• Este es el código fuente del archivo de proyecto predeterminado para una


nueva aplicación que tiene un formulario llamado "Form1:"

• > programa Project1; usa Formularios, Unidad1 en 'Unidad1.pas' { Formulario1 } ; {$


R * .RES} begin Application.Initialize; Application.CreateForm (TForm1,
Form1); Aplicación.Ejecutar; fin

• A continuación hay una explicación de cada uno de los componentes del


archivo PAS:

• " programa "

• Esta palabra clave identifica a esta unidad como la unidad fuente principal
del programa. Puede ver que el nombre de la unidad, "Proyecto1", sigue la
palabra clave del programa. Delphi le da al proyecto un nombre
predeterminado hasta que lo guarde como algo diferente.

• Cuando ejecuta un archivo de proyecto desde el IDE, Delphi usa el nombre


del archivo de Proyecto para el nombre del archivo EXE que crea. Lee la
cláusula "usos" del archivo de proyecto para determinar qué unidades son
parte de un proyecto.

• " {$ R * .RES} "

• El archivo DPR está vinculado al archivo PAS con la directiva de


compilación {$ R * .RES} . En este caso, el asterisco representa la raíz del
nombre del archivo PAS en lugar de "cualquier archivo". Esta directiva de
compilación le dice a Delphi que incluya el archivo de recursos de este
proyecto, como su imagen de icono.

• " comenzar y terminar "

• El bloque "comenzar" y "finalizar" es el bloque de código fuente principal


para el proyecto.

• " Inicializar "

• Aunque "Inicializar" es el primer método llamado en el código


fuente principal, no es el primer código que se ejecuta en una aplicación. La
aplicación primero ejecuta la "inicialización" sección de todas las unidades
utilizadas por la aplicación.

• " Application.CreateForm "


• La instrucción "Application.CreateForm" carga el formulario especificado en
su argumento. Delphi agrega una declaración Application.CreateForm al
archivo de proyecto para cada formulario que se incluye.

• El trabajo de este código es asignar primero memoria para el formulario.


Las declaraciones se enumeran en el orden en que los formularios se
agregan al proyecto. Este es el orden en que se crearán los formularios en
la memoria en tiempo de ejecución.

• Si desea cambiar este orden, no edite el código fuente del proyecto. En su


lugar, use el menú Proyecto> Opciones .

• " Aplicación.Ejecutar "

• La instrucción "Application.Run" inicia la aplicación. Esta instrucción le dice


al objeto pre-declarado llamado Aplicación, que comience a procesar los
eventos que ocurren durante la ejecución de un programa.

• Ejemplo de ocultar el formulario principal / botón de la barra de tareas


• La propiedad "ShowMainForm" del objeto Aplicación determina si un
formulario se mostrará o no al inicio. La única condición para establecer
esta propiedad es que debe llamarse antes de la línea "Application.Run".

• > // Presumir: Form1 es el FORMULARIO PRINCIPAL Application.CreateForm


(TForm1, Form1); Application.ShowMainForm: = Falso; Aplicación.Ejecutar;

Comprender las constantes tipadas en


Delphi
• by Zarko Gajic
• Cómo implementar valores persistentes entre llamadas a funciones.

• Cuando Delphi invoca un controlador de eventos, los antiguos valores de


las variables locales se anulan. ¿Qué pasa si queremos hacer un
seguimiento de cuántas veces se ha hecho clic en un botón? Podríamos
mantener los valores usando una variable de nivel de unidad, pero
generalmente es una buena idea reservar variables de nivel de unidad solo
para compartir información. Lo que necesitamos se suele llamar variables
estáticas o constantes tipadas en Delphi.

• ¿Variable o constante?
• Las constantes tipadas se pueden comparar con variables inicializadas: variables
cuyos valores se definen al ingresar a su bloque (generalmente controlador de
eventos). Dicha variable se inicializa solo cuando el programa comienza a
ejecutarse. Después de eso, el valor de una constante tipeada persiste entre
llamadas sucesivas a sus procedimientos.

• El uso de constantes tipadas es una forma muy limpia de implementar


variables inicializadas automáticamente. Para implementar estas variables
sin constantes tipadas, necesitaremos crear una sección de inicialización
que establezca el valor de cada variable inicializada.

• Constantes de tipo variable


• Aunque declaramos constantes tipadas en la sección const de un procedimiento, es
importante recordar que no son constantes. En cualquier punto de su aplicación, si
tiene acceso al identificador de una constante tipeada, podrá modificar su valor.

• Para ver las constantes escritas en el trabajo, coloque un botón en un


formulario en blanco y asigne el siguiente código al controlador de eventos
OnClick:

• > procedure TForm1.Button1Click (Sender: TObject); clics const : entero = 1; // no es


una constante verdadera begin Form1.Caption: = IntToStr (clicks); clics: = clics +
1; fin ; Tenga en cuenta que cada vez que hace clic en el botón, forma incrementos
de leyendas constantemente.
Ahora intente con el siguiente código: > procedure TForm1.Button1Click (Sender:
TObject); var clics: Entero; comenzar Form1.Caption: = IntToStr (clics); clics: = clics +
1; fin ; Ahora estamos usando una variable no inicializada para el contador de clics.
Observe ese valor extraño en el título de formularios después de hacer clic en el
botón.

• Constantes tipadas constantes


• Debes aceptar que la idea de las constantes modificables suena un poco extraña.
En versiones de 32 bits de Delphi Borland decidió desalentar su uso, pero los
admite para el código heredado Delphi 1.

• Podemos habilitar o deshabilitar las constantes tipeadas asignables en la


página del compilador del cuadro de diálogo Opciones del proyecto.

• Si ha desactivado las constantes tipeables asignables para un proyecto


determinado, cuando intente compilar el código anterior, Delphi le dará el
error "No se puede asignar el lado izquierdo" en la compilación. Sin
embargo, puede crear una constante tipada asignable declarando:

• > {$ J +} clics const : Entero = 1; {$ J-} Por lo tanto, el primer código de ejemplo se
ve así: > procedure TForm1.Button1Click (Sender: TObject); const {$ J +} clics: Entero
= 1; // no es una constante verdadera {$ J-} begin Form1.Caption: = IntToStr
(clicks); clics: = clics + 1; fin ;
• Conclusión
• Depende de usted decidir si desea que las constantes mecanografiadas sean
asignables o no. Lo importante aquí es que además de ser ideal para contadores,
las constantes tipadas son ideales para hacer que los componentes sean
alternativamente visibles o invisibles, o podemos usarlos para alternar entre
cualquier propiedad booleana. Las constantes tipadas también se pueden usar
dentro del controlador de eventos de TTimer para realizar un seguimiento de
cuántas veces se ha disparado.
Si desea más material para principiantes, consulte el resto de los temas de
programación de Delphi For Beginners.

Crear formulario Delphi a partir de una


cadena
• by Zarko Gajic

Puede haber instancias en las que no conozca el tipo de clase exacto de un objeto
de formulario . Solo puede tener la variable de cadena que lleva el nombre de la
clase del formulario, como "TMyForm".

Tenga en cuenta que el procedimiento Application.CreateForm () espera una


variable de tipo TFormClass para su primer parámetro. Si puede proporcionar una
variable de tipo TFormClass (a partir de una cadena), podrá crear un formulario a
partir de su nombre.

La función FindClass () Delphi localiza un tipo de clase de una cadena . La


búsqueda pasa por todas las clases registradas. Para registrar una clase, se
puede emitir un procedimiento RegisterClass () . Cuando la función FindClass
devuelve un valor de TPersistentClass, transfiéralo a TFormClass, y se creará un
nuevo objeto TForm.

Un ejercicio de muestra

1. Cree un nuevo proyecto Delphi y nombre el formulario principal: MainForm


(TMainForm).
2. Agregue tres formularios nuevos al proyecto, asígneles un nombre:
▪ FirstForm (TFirstForm)
▪ SecondForm (TSecondForm)
▪ ThirdForm (TThirdForm)
3. Elimine los tres nuevos formularios de la lista "Crear automáticamente
formularios" en el cuadro de diálogo Opciones de proyecto.
4. Coloque un ListBox en MainForm y agregue tres cadenas: 'TFirstForm',
'TSecondForm' y 'TThirdForm'.
procedure TMainForm.FormCreate (Sender: TObject); comenzar RegisterClass
(TFirstForm); RegisterClass (TSecondForm); RegisterClass (TThirdForm); fin ;
En el evento OnCreate de MainForm registra las clases:

procedimiento TMainForm.CreateFormButtonClick (Sender: TObject); var s:


cadena; begin s: = ListBox1.Items [ListBox1.ItemIndex]; CreateFormFromName
(s); fin ;
Una vez que se hace clic en el botón, busque el nombre de tipo del formulario
seleccionado y llame a un procedimiento personalizado CreateFormFromName:

procedimiento CreateFormFromName ( const FormName: string ); var fc:


TFormClass; f: TForm; begin fc: = TFormClass (FindClass (FormName)); f: = fc.Create
(Aplicación); f.Mostrar; fin ; (* CreateFormFromName *)
Si se selecciona el primer elemento en el cuadro de lista, la variable "s" contendrá
el valor de cadena "TFirstForm". CreateFormFromName creará una instancia del
formulario TFirstForm.

Más sobre la creación de formularios Delphi

▪ Arrastre un formulario de Delphi sin la barra de título


▪ Comunicación entre formularios
▪ Comprender el ciclo de vida de un formulario de Delphi

Comprender el tipo de SET Delphi


• by Zarko Gajic

if ModalResult in [mrYes, mrOk] luego ...

Una de las características del lenguaje Delphi que no se encuentra en otros


idiomas modernos es la noción de conjuntos.

El tipo de conjunto de Delphi es una colección de valores del mismo tipo ordinal .

Un conjunto se define utilizando el conjunto de palabra clave:


> escriba TMagicNumber = 1..34; TMagicSet =
conjunto de TMagicNumber; var emptyMagicSet: TMagicSet; oneMagicSet:
TMagicSet; anotherMagicSet: TMagicSet; begin emptyMagicSet: = []; oneMagicSet: = [1, 18,
24]; anotherMagicSet: = [2, 5, 19]; if 1 in oneMagicSet then ShowMessage ('1 es mágico,
parte de oneMagicSet'); fin ;

Los tipos de conjuntos generalmente se definen con subrangos .

En el ejemplo anterior, el TMagicNumber es un tipo de subrango personalizado


que permite que las variables del tipo TMagicNumber reciban valores del 1 al 34.
En pocas palabras, un tipo de subrango representa un subconjunto de los valores
en otro tipo ordinal.

Los valores posibles del tipo de conjunto son todos los subconjuntos del tipo base,
incluido el conjunto vacío.

Una limitación de los conjuntos es que pueden contener hasta 255 elementos.

En el ejemplo anterior, el tipo de conjunto TMagicSet es un conjunto de elementos


TMagicNumber: números enteros del 1 al 34.

La declaración TMagicSet = set de TMagicNumber es igual a la siguiente


declaración: TMagicSet = set of 1..34.

Establecer variables de tipo


En el ejemplo anterior, las
variables emptyMagicSet , oneMagicSet y anotherMagicSet son conjuntos de
TMagicNumber.

Para asignar un valor a una variable de tipo de conjunto, utilice los corchetes y
enumere todos los elementos del conjunto. Como en:

> oneMagicSet: = [1, 18, 24];

Nota 1: cada variable de tipo de conjunto puede contener el conjunto vacío,


indicado por [].

Nota 2: el orden de los elementos en un conjunto no tiene significado, ni es


significativo que un elemento (valor) se incluya dos veces en un conjunto.

La palabra clave IN
Para probar si un elemento está incluido en el conjunto (variable) use la palabra
clave IN :

> si 1 en unoMagicSet, entonces ...


Establecer operadores
De la misma manera que puede sumar dos números, puede tener un conjunto que
es la suma de dos conjuntos. Con los sets, tu evento tiene más operadores:

▪ + devuelve la unión de dos conjuntos.


▪ - devuelve la diferencia de dos conjuntos.
▪ * devuelve la intersección de dos conjuntos.
▪ = devuelve verdadero si dos conjuntos son iguales - tienen el mismo elemento.
▪ <= devuelve verdadero si el primer conjunto es un subconjunto del segundo conjunto.
▪ > = devuelve verdadero si el primer conjunto es un superconjunto del segundo
conjunto.
▪ <> devuelve verdadero si dos conjuntos no son idénticos.
▪ IN devuelve verdadero si un elemento está incluido en el conjunto.
Aquí hay un ejemplo:

> emptyMagicSet: = oneMagicSet + anotherMagicSet; emptyMagicSet: = emptyMagicSet -


[1]; emptyMagicSet: = emptyMagicSet + [5,10]; if emptyMagicSet =
[2,5,10,18,19,24] luego comience emptyMagicSet: = emptyMagicSet *
oneMagicSet; ShowMessage (DisplayElements (emptyMagicSet)); fin ;

¿Se ejecutará el procedimiento ShowMessage? Si es así, ¿qué se mostrará?

Aquí está la implementación de la función DisplayElements:

> función DisplayElements (magicSet: TMagicSet): cadena ; elemento var :


TMagicNumber; begin for element en magicSet do result: = resultado + IntToStr (elemento)
+ '| '; fin ;

Sugerencia: sí. Mostrado: "18 | 24 |".

Enteros, caracteres, booleanos


Por supuesto, al crear tipos de conjuntos, no está restringido a valores enteros.
Los tipos ordinales de Delphi incluyen caracteres y valores booleanos.

Para evitar que los usuarios escriban teclas alfabéticas, agregue esta línea
en OnKeyPress de un control de edición:

> if Teclee ['a' .. 'z'] + ['A' .. 'Z'] luego Key: = # 0

Conjuntos con enumeraciones


Un escenario comúnmente utilizado en el código Delphi es mezclar los tipos
enumerados y los tipos establecidos.
Aquí hay un ejemplo:

> escriba TWorkDay = (lunes, martes, miércoles, jueves, viernes); TDaySet = conjunto
de TWorkDay; var días: TDaySet; comenzar días: = [lunes, viernes]; días: = días + [martes,
jueves] - [viernes]; si miércoles EN días, luego ShowMessage ('Me encanta el miércoles!');

Pregunta: ¿se mostrará el mensaje? Respuesta: no :(

Conjuntos en propiedades de control de Delphi


Cuando necesite aplicar "negrita" a la fuente utilizada en los controles de TEdit,
puede usar el Inspector de Objetos o el siguiente código:

> Font.Style: = Font.Style + [fsBold];

¡La propiedad Style de Font es una propiedad de tipo set! Así es como se define:

> escriba TFontStyle = (fsBold, fsItalic, fsUnderline, fsStrikeOut); TFontStyles = conjunto


de TFontStyle; ... propiedad Estilo: TFontStyles ...

Por lo tanto, un tipo enumerado TFontStyle se utiliza como el tipo base para el tipo
de conjunto TFontStyles. La propiedad Style de la clase TFont es de tipo
TFontStyles, por lo tanto, una propiedad de tipo set.

Otro ejemplo incluye el resultado de la función MessageDlg. Una función


MessageDlg se utiliza para mostrar un cuadro de mensaje y obtener la respuesta
del usuario. Uno de los parámetros de la función es el parámetro Botones de tipo
TMsgDlgButtons.

TMsgDlgButtons se define como un conjunto de (mbYes, mbNo, mbOK,


mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToAll, mbYesToAll,
mbHelp).

Si muestra un mensaje para el usuario que contiene los botones Sí, Aceptar y
Cancelar y desea ejecutar algún código si se hizo clic en los botones Sí o Aceptar,
puede usar el siguiente código:

> si MessageDlg ('Aprendiendo sobre Sets!', mtInformation, [mbYes, mbOk, mbCancel],


0) en [mrYes, mrOK] luego ...

Palabra final: los conjuntos son geniales. Los conjuntos pueden parecer confusos
para un principiante de Delphi, pero tan pronto como empiece a usar variables de
tipo de conjunto descubrirá que proporcionan mucho más de lo que sonaba al
principio. Al menos tengo :))
Historia de Delphi - de Pascal a
Embarcadero Delphi XE 2
• by Zarko Gajic
• Historia de Delphi: las raíces

• Este documento proporciona descripciones concisas de las versiones de


Delphi y su historial, junto con una breve lista de características y notas.
Descubra cómo Delphi evolucionó de Pascal a una herramienta RAD que
puede ayudarlo a resolver problemas de desarrollo complejos para ofrecer
aplicaciones de alto rendimiento y escalables que van desde aplicaciones
de escritorio y bases de datos hasta aplicaciones móviles y distribuidas
para Internet, no solo para Windows, sino también para Linux y .NET.

• Que es Delphi?
Delphi es un lenguaje de alto nivel, compilado y fuertemente tipado que
admite el diseño estructurado y orientado a objetos . El lenguaje Delphi se
basa en Object Pascal. Hoy, Delphi es mucho más que simplemente el
"lenguaje Object Pascal".

• Las raíces: Pascal y su historia


El origen de Pascal le debe gran parte de su diseño a Algol, el primer
lenguaje de alto nivel con una sintaxis legible, estructurada y definida
sistemáticamente. A finales de los años sesenta (196X), se desarrollaron
varias propuestas para un sucesor evolutivo de Algol. El más exitoso fue
Pascal, definido por el Prof. Niklaus Wirth. Wirth publicó la definición original
de Pascal en 1971. Se implementó en 1973 con algunas modificaciones.
Muchas de las características de Pascal provienen de idiomas anteriores.
La declaración de caso y el paso de parámetros de resultado de valor
provino de Algol, y las estructuras de registros fueron similares a Cobol y
PL 1. Además de eliminar o eliminar algunas de las características más
oscuras de Algol, Pascal agregó la capacidad de definir nuevos tipos de
datos de más simples existentes.

• Pascal también admitió estructuras de datos dinámicas; es decir,


estructuras de datos que pueden crecer y reducirse mientras se ejecuta un
programa. El lenguaje fue diseñado para ser una herramienta de
enseñanza para los estudiantes de las clases de programación.

• En 1975, Wirth y Jensen produjeron el último libro de referencia de Pascal,


"Manual de usuario e informe de Pascal".

• Wirth detuvo su trabajo en Pascal en 1977 para crear un nuevo lenguaje,


Modula, el sucesor de Pascal.
• Borland Pascal
Con el lanzamiento (noviembre de 1983) de Turbo Pascal 1.0, Borland
comenzó su viaje al mundo de los entornos y herramientas de desarrollo.
Para crear Turbo Pascal 1.0, Borland licenció el rápido y económico núcleo
del compilador Pascal, escrito por Anders Hejlsberg. Turbo Pascal presentó
un Entorno de desarrollo integrado (IDE) donde puede editar el código,
ejecutar el compilador, ver los errores y volver a las líneas que contienen
esos errores. El compilador de Turbo Pascal ha sido una de las series de
compiladores más vendidas de todos los tiempos, y ha hecho que el
lenguaje sea especialmente popular en la plataforma de PC.

• En 1995, Borland revivió su versión de Pascal cuando introdujo el entorno


de desarrollo de aplicaciones rápidas llamado Delphi, convirtiendo a Pascal
en un lenguaje de programación visual. La decisión estratégica fue hacer
que las herramientas de base de datos y la conectividad fueran una parte
central del nuevo producto Pascal.

• Las raíces: Delphi


Después del lanzamiento de Turbo Pascal 1, Anders se unió a la compañía
como empleado y fue el arquitecto de todas las versiones del compilador de
Turbo Pascal y las primeras tres versiones de Delphi. Como arquitecto jefe
de Borland, Hejlsberg convirtió secretamente Turbo Pascal en un lenguaje
de desarrollo de aplicaciones orientado a objetos, completo con un entorno
verdaderamente visual y excelentes características de acceso a la base de
datos: Delphi.

• Lo que sigue en las próximas dos páginas es una descripción concisa de


las versiones de Delphi y su historia, junto con una breve lista de
características y notas.

• Ahora que sabemos qué es Delphi y dónde están sus raíces, es hora de
hacer un viaje al pasado ...

• ¿Por qué el nombre "Delphi"?


Como se explica en el artículo del Museo Delphi, el proyecto cuyo nombre
en clave es Delphi nació a mediados de 1993. ¿Por qué Delphi? Era simple:
"Si quieres hablar con [el] Oracle, ve a Delphi". Cuando llegó el momento
de elegir el nombre de un producto minorista, después de un artículo en
Windows Tech Journal sobre un producto que cambiará la vida de los
programadores, el nombre propuesto (final) fue AppBuilder.

• Desde que Novell lanzó su Visual AppBuilder, los chicos de Borland


tuvieron que elegir otro nombre; se convirtió en algo así como una comedia:
mientras más difícil era la gente de despedir a "Delphi" por el nombre del
producto, más ganaba apoyo. Una vez promocionado como el "asesino de
VB", Delphi se ha mantenido como un producto fundamental para Borland.
• Nota: algunos de los enlaces a continuación marcados con un asterisco (*),
utilizando Internet Archive WayBackMachine, le llevarán varios años en el
pasado, mostrando cómo se veía el sitio Delphi hace mucho tiempo.
El resto de los enlaces lo guiarán a una mirada más profunda sobre de qué
se trata cada tecnología (nueva), con tutoriales y artículos.

• Delphi 1 (1995)
Delphi, la poderosa herramienta de desarrollo de programación de Windows
de Borland apareció por primera vez en 1995. Delphi 1 extendió el lenguaje
de Borland Pascal al proporcionar un enfoque orientado a objetos y
formularios, compilador de código nativo extremadamente rápido,
herramientas visuales de dos vías y excelente soporte de base de datos,
integración cercana con Windows y la tecnología de componentes.

• Aquí está el primer borrador de la biblioteca de componentes visuales

• Lema de Delphi 1 * :
Delphi y Delphi Client / Server son las únicas herramientas de desarrollo
que ofrecen los beneficios del desarrollo de aplicaciones rápidas (RAD) del
diseño basado en componentes visuales, el poder de un compilador de
código nativo optimizado y una solución cliente / servidor escalable.

• Estas son las "7 principales razones para comprar Borland Delphi 1.0 Client
/ Server * "

• Delphi 2 (1996)
Delphi 2 * es la única herramienta de desarrollo rápido de aplicaciones que
combina el rendimiento del compilador de código nativo de 32 bits más
rápido del mundo, la productividad del diseño basado en componentes
visuales y la flexibilidad de la arquitectura de base de datos escalable en un
entorno robusto orientado a objetos .

• Delphi 2, además de ser desarrollado para la plataforma Win32 (soporte


completo de Windows 95 e integración), trajo una red de base de datos
mejorada, automatización OLE y soporte de tipos de datos variantes, el tipo
de datos de cadena larga y la herencia de formularios visuales. Delphi 2: "la
facilidad de VB con el poder de C ++"

• Delphi 3 (1997)
El conjunto más completo de herramientas de desarrollo visual, de alto
rendimiento para clientes y servidores para crear aplicaciones
empresariales y web distribuidas.

• Delphi 3 * introdujo nuevas características y mejoras en las siguientes


áreas: la tecnología de visión de código, depuración DLL, plantillas de
componentes, los componentes DecisionCube y TeeChart , la tecnología
WebBroker, ActiveForms, paquetes de componentes e integración con
COM mediante interfaces.
• Delphi 4 (1998)
Delphi 4 * es un conjunto completo de herramientas profesionales y de
desarrollo de cliente / servidor para la creación de soluciones de alta
productividad para computación distribuida. Delphi proporciona
interoperabilidad Java, controladores de base de datos de alto rendimiento,
desarrollo CORBA y compatibilidad con Microsoft BackOffice. Nunca has
tenido una forma más productiva de personalizar, administrar, visualizar y
actualizar datos. Con Delphi, usted entrega aplicaciones robustas a la
producción, a tiempo y dentro del presupuesto.

• Delphi 4 introdujo componentes de acoplamiento, anclaje y restricción. Las


nuevas características incluyen AppBrowser, matrices
dinámicas , sobrecarga de métodos , compatibilidad con Windows 98,
compatibilidad mejorada con OLE y COM, así como compatibilidad con
bases de datos extendidas.

• Delphi 5 (1999)
Desarrollo de alta productividad para Internet

• Delphi 5 * presentó muchas características y mejoras nuevas. Algunos,


entre muchos otros, son: varios diseños de escritorio, el concepto de
marcos, desarrollo paralelo, capacidades de traducción , depurador
integrado mejorado, nuevas capacidades de Internet ( XML ), más potencia
de base de datos ( soporte ADO ), etc.

• Luego, en 2000, Delphi 6 fue la primera herramienta para soportar


completamente los servicios web nuevos y emergentes ...

• Lo que sigue es una descripción concisa de las versiones más recientes de


Delphi, junto con una breve lista de características y notas.

• Delphi 6 (2000)
Borland Delphi es el primer entorno de desarrollo rápido de aplicaciones
para Windows que es totalmente compatible con los servicios web nuevos y
emergentes. Con Delphi, los desarrolladores corporativos o individuales
pueden crear aplicaciones de e-business de próxima generación rápida y
fácilmente.

• Delphi 6 presentó nuevas características y mejoras en las siguientes áreas:


IDE, Internet, XML, compilador, COM / Active X, soporte de base de datos
...


Además, Delphi 6 agregó el soporte para el desarrollo multiplataforma, lo
que permite compilar el mismo código con Delphi (en Windows) y Kylix
(bajo Linux). Más mejoras incluidas: soporte para servicios web, el motor
DBExpress , nuevos componentes y clases ...
• Delphi 7 (2001)
Borland Delphi 7 Studio proporciona la ruta de migración a Microsoft .NET
que los desarrolladores han estado esperando. Con Delphi, las opciones
son siempre tuyas: tienes el control de un estudio de desarrollo de e-
business completo, con la libertad de llevar fácilmente tus soluciones
multiplataforma a Linux.

• Delphi 8
Para el octavo aniversario de Delphi, Borland preparó el lanzamiento más
importante de Delphi: Delphi 8 continúa proporcionando Visual Component
Library (VCL) y Component Library para desarrollo multiplataforma
(CLX) para Win32 (y Linux), así como nuevas características y continúa
mejoras en el marco, compilador, IDE y tiempo de diseño.

• Delphi 2005 (parte de Borland Developer Studio 2005)


Diamondback es el nombre clave de la próxima versión de Delphi. El nuevo
Delphi IDE admite múltiples personalidades. Es compatible con Delphi para
Win 32, Delphi para .NET y C # ...

• Delphi 2006 (parte de Borland Developer Studio 2006)


BDS 2006 (código denominado "DeXter") incluye soporte RAD completo
para C ++ y C # además de Delphi para Win32 y Delphi para lenguajes de
programación .NET.

• Turbo Delphi : para el desarrollo de Win32 y .Net


La línea de productos Turbo Delphi es un subconjunto del BDS 2006.

• CodeGear Delphi 2007


Delphi 2007 lanzado en marzo de 2007. Delphi 2007 para Win32 está
dirigido principalmente a los desarrolladores de Win32 que desean
actualizar sus proyectos existentes para incluir soporte completo de Vista:
aplicaciones temáticas y soporte VCL para vidrio, diálogos de archivos y
componentes de Dialog de tareas.

• Embarcadero Delphi 2009


Embarcadero Delphi 2009 . Soporte para .Net eliminado. Delphi 2009 tiene
soporte unicode, nuevas funciones de lenguaje como Generics y métodos
anónimos, los controles Ribbon, DataSnap 2009 ...

• Embarcadero Delphi 2010


Embarcadero Delphi 2010 lanzado en 2009. Delphi 2010 le permite crear
interfaces de usuario basadas en el tacto para tabletas, touchpad y
aplicaciones de kiosco.

• Embarcadero Delphi XE
Embarcadero Delphi XE lanzado en 2010. Delphi 2011, trae muchas
características y mejoras nuevas: gestión integrada de código fuente,
desarrollo de nube incorporado (Windows Azure, Amazon EC2), innovador
cofre de herramientas expandido para desarrollo optimizado, DataSnap
desarrollo de múltiples niveles , mucho más...

• Embarcadero Delphi XE 2
Embarcadero Delphi XE 2 lanzado en 2011. Delphi XE2 le permitirá: crear
aplicaciones Delphi de 64 bits, usar el mismo código fuente para apuntar a
Windows y OS X, crear aplicaciones FireMonkey (HD y 3D de negocios),
ampliar múltiples aplicaciones DataSnap de nivel con nueva conectividad
móvil y en la nube en RAD Cloud, use estilos VCL para modernizar el
aspecto de sus aplicaciones ...

Una guía para usar el TClientDataSet en


aplicaciones Delphi
• by Zarko Gajic
• ¿Está buscando una base de datos de un solo usuario para su próxima
aplicación Delphi? ¿Necesita almacenar algunos datos específicos de la
aplicación pero no desea usar el Registro / INI / o algo más?

• Delphi ofrece una solución nativa: el componente TClientDataSet, ubicado


en la pestaña " Acceso a datos " de la paleta de componentes, representa
un conjunto de datos independiente de la base de datos en memoria. Si
utiliza conjuntos de datos de cliente para datos basados en archivos,
actualizaciones de caché, datos de un proveedor externo (como
trabajar con un documento XML o en una aplicación de varios niveles), o
una combinación de estos enfoques en una aplicación de "modelo de
maletín", aproveche la amplia gama de características que admiten los
conjuntos de datos de los clientes.

• Conjuntos de datos Delphi


• Un ClientDataSet en cada aplicación de base de datos
Aprenda el comportamiento básico de ClientDataSet y encuentre un
argumento para el uso extensivo de ClientDataSets en la mayoría de
las aplicaciones de bases de datos .

• Definición de la estructura de ClientDataSet utilizando FieldDefs


Al crear un almacenamiento de memoria de ClientDataSet sobre la marcha,
debe definir explícitamente la estructura de su tabla. Este artículo muestra
cómo hacerlo tanto en tiempo de ejecución como en tiempo de diseño
usando FieldDefs.

• Definición de la estructura de ClientDataSet utilizando TFields


Este artículo muestra cómo definir la estructura de ClientDataSet tanto en
tiempo de diseño como en tiempo de ejecución utilizando TFields. Los
métodos para crear campos de datos anidados y virtuales también se
demuestran.

• Comprender los índices de ClientDataSet


Un ClientDataSet no obtiene sus índices de los datos que carga. Los
índices, si los quiere, deben estar explícitamente definidos. Este artículo
muestra cómo hacerlo en tiempo de diseño o en tiempo de ejecución.

• Navegación y edición de un ClientDataSet


Navega y edita un ClientDataSet de forma similar a cómo navega y edita
casi cualquier otro conjunto de datos. Este artículo brinda una introducción
a la navegación y edición básica de ClientDataSet.

• Buscando un ClientDataSet
ClientDataSets proporciona varios mecanismos diferentes para buscar
datos en sus columnas.

• Estas técnicas están cubiertas en esta continuación de la discusión de la


manipulación básica de ClientDataSet.

• Filtrado de ClientDataSets
Cuando se aplica a un conjunto de datos, un filtro limita los registros a los
que se puede acceder. Este artículo explora las entradas y salidas del
filtrado de ClientDataSets.

• ClientDataSet agregados y GroupState


Este artículo describe cómo usar agregados para calcular estadísticas
simples, así como también cómo usar el estado del grupo para mejorar sus
interfaces de usuario.

• Anidar DataSets en ClientDataSets


Un conjunto de datos anidados es un conjunto de datos dentro de un
conjunto de datos. Al anidar un conjunto de datos dentro de otro, puede
reducir sus necesidades generales de almacenamiento, aumentar la
eficiencia de las comunicaciones de red y simplificar las operaciones de
datos.

• Clonación de cursores de ClientDatSet


Cuando clona el cursor de un ClientDataSet, crea no solo un puntero
adicional a un almacén de memoria compartido sino también una vista
independiente de los datos. Este artículo te muestra cómo usar esta
importante función

• Implementación de aplicaciones que usan ClientDataSets


Si usa uno o más ClientDataSets, puede necesitar implementar una o más
bibliotecas, además del ejecutable de su aplicación. Este artículo describe
cuándo y cómo implementarlos.
• Soluciones creativas utilizando ClientDataSets
ClientDataSets se puede utilizar para mucho más que mostrar filas y
columnas desde una base de datos.

• Vea cómo solucionan los problemas de las aplicaciones, incluida la


selección de opciones para procesar, la visualización de los mensajes de
progreso y la creación de pistas de auditoría para los cambios de datos.

Uso del componente TDBGrid


• by Zarko Gajic
• DBGrid al máximo

• Contrariamente a la mayoría de los demás controles Delphi, el componente


DBGrid tiene muchas características agradables y es más poderoso de lo
que piensas.

• A continuación se detallan las formas en que puede aprovechar al máximo


el componente TDBGrid Delphi, separado en categorías.

• Los basicos
• Puede hacer que la tecla Intro funcione como la tecla Tab en un DBGrid,
que también permite que Shift + Enter funcione como lo haría si se
usara Tab + Enter .

• Vea cómo corregir los anchos de columna DBGrid automáticamente (en


tiempo de ejecución) para eliminar el espacio no ocupado en el borde
derecho de la cuadrícula.

• Ajustará automáticamente el ancho de la columna para adaptarse incluso a


la entrada más amplia.

• También puede mejorar la funcionalidad de un componente TDBgrid


usando colores (filas de colores, columnas, celdas, dependiendo de un
valor de campo).

• Siga este tutorial para ver cómo mostrar los contenidos de un campo
MEMO (BLOB textual) en un TDBGrid, además de cómo habilitar la edición
de los MEMO.

• Algunos otros tutoriales ingeniosos


• Cuando la propiedad Opciones de DBGrid
incluye dgRowSelect y dgMultiSelect , los usuarios pueden seleccionar
múltiples filas dentro de la grilla .

• Una de las maneras más naturales y fáciles de dejar que los usuarios
clasifiquen una columna es hacer que hagan clic en el título de la columna.
Siga nuestra guía sobre cómo ordenar registros en Delphi DBGrid para
obtener toda la información que necesita para que esto suceda.

• Vea cómo recuperar, visualizar y editar hojas de cálculo de Microsoft


Excel con ADO (dbGO) y Delphi para aprender cómo conectarse a Excel,
recuperar los datos de la hoja y habilitar esos datos para ser editados
usando DBGrid.

• También encontrará una lista de los errores más comunes que pueden
aparecer durante el proceso, además de cómo tratarlos.

• Guías avanzadas
• ¿Necesitas resaltar la fila detrás del cursor del mouse en un DBGrid? Te
tenemos cubierto . Hace que la lectura de los datos sea mucho más fácil
cuando se ilumina toda la fila. Averigüe cómo seleccionar (hacer activo) y
resaltar (cambiar el color, fuente, etc.) una fila en un DBGrid a medida que
el mouse se mueve alrededor de la grilla.

• Aquí se explica cómo colocar casi cualquier control Delphi (componente


visual) en una celda de una DGBrid, como casillas de verificación (usando
un control TChekBox).

Aplicaciones Skinning Delphi


• by Zarko Gajic
• Cambie la apariencia de sus aplicaciones Delphi - ¡Agregue temas y
máscaras!

• Estos componentes de Delphi cambian la apariencia de las aplicaciones al


agregar temas y máscaras. Es una forma fácil de mejorar la interfaz gráfica
de usuario (GUI).

• VCLSkin
• VCLSkin es un componente fácil de usar para crear una GUI para una
aplicación Delphi. VCLSkin tematizará o despellejará toda la aplicación sin
ninguna modificación del código fuente. Más "

• DynamicSkinForm
• La biblioteca DynamicSkinForm VCL brinda soporte para formularios,
menús, sugerencias y muchos controles originales estándar y no estándar.
Las máscaras tienen muchos objetos y efectos para aplicaciones geniales
estándar y no estándar como WinAmp e iTunes. Un editor especial permite
al usuario crear máscaras personalizadas. SkinAdapter es un componente
de DynamicSkinForm que permite desvelar las aplicaciones sin modificar el
código fuente. Más "
• SUISkin
• SUISkin ofrece una aplicación automática compatible con la piel. Con
SUISkin, no se requieren modificaciones para los proyectos existentes.
Simplemente suelte el componente del motor de la piel en el formulario
principal y establezca algunas propiedades. Piel todas las formas y cuadros
de diálogo automáticamente. Los archivos de máscara se pueden compilar
en el archivo EXE. En tiempo de ejecución, puede cambiar o desactivar las
máscaras fácilmente. Más »

• AppFace
• El Kit de desarrollo de la interfaz de usuario de AppFace es una solución de
desarrollo de interfaz gráfica de usuario de aplicación visual que se puede
usar en VC, C #, VB.Net, Delphi, Visual Basic, C ++ Builder y Win32 SDK.
Incluye control de skinning, creador visual de skin, código fuente de
muestra en VC, C #, VB.Net, Delphi, Visual Basic, C ++ Builder y Win32
SDK, así como un manual técnico. La biblioteca de skinning, appface.dll, es
el componente kernel; puede cubrir todas las ventanas creadas
automáticamente en la aplicación de destino. Más "

• SkinFeature
• skinfeature usa efectos especiales creativos para un desarrollo de GUI
totalmente interactivo. skinfeature es compatible con una amplia gama de
lenguajes de desarrollo, herramientas y frameworks, incluyendo Visual
Basic, Visual C ++, Delphi, Borland C ++ Builder, Microsoft DotNet y Win32
SDK. Más "

Usando TDictionary para tablas Hash en


Delphi
• by Zarko Gajic
• Introducido en Delphi 2009, la clase TDictionary , definida en la unidad
Generics.Collections, representa una colección genérica de tipos de tabla
hash de pares clave-valor.

• Los tipos genéricos , también introducidos en Delphi 2009, le permiten


definir clases que no definen específicamente el tipo de miembros de datos.

• Un diccionario es, en cierto modo, similar a una matriz. En una matriz, usted
trabaja con una serie (colección) de valores indexados por un valor entero,
que puede ser cualquier valor de tipo ordinal .

• Este índice tiene un límite inferior y un límite superior.

• En un diccionario puede almacenar claves y valores donde cualquiera


puede ser de cualquier tipo.
• El constructor TDictionary
• De ahí la declaración del constructor TDictionary:

• > TDictionary .Crear;

• En Delphi, el TDictionary se define como una tabla hash. Las tablas hash
representan una colección de pares clave-valor que se organizan en
función del código hash de la clave. Las tablas Hash están optimizadas
para búsquedas (velocidad). Cuando se agrega un par clave-valor a una
tabla hash, el hash de la clave se calcula y se almacena junto con el par
agregado.

• El TKey y TValue, porque son genéricos, pueden ser de cualquier tipo. Por
ejemplo, si la información que debe almacenar en el diccionario proviene de
alguna base de datos, su clave puede ser un valor GUID (u otro valor que
presente el índice exclusivo), mientras que el valor puede ser un objeto
asignado a una fila de datos en sus tablas de base de datos.

• Usando TDictionary
• En aras de la simplicidad, el siguiente ejemplo utiliza enteros para TKeys y
caracteres para TValues.

• > // // "log" es un control TMemo colocado en un formulario // var dict:


TDictionary ; sortedDictKeys: TList ; i, rnd: entero; c: char; comenzar el registro.
Borrar; log.Text: = 'muestras de uso de TDictionary'; Aleatorizar; dict: =
TDictionary .Create; intente // agregue algunos pares de clave / valor (enteros
aleatorios, caracteres aleatorios de A en ASCII) para i: = 1 a 20 do comienzan rnd: =
Aleatorio (30); si NO dict.ContainsKey (rnd) then dict.Add (rnd, Char (65 +
rnd)); fin ; // eliminar algunos pares de clave / valor (enteros aleatorios, caracteres
aleatorios de A en ASCII) para i: = 1 a 20 do comienzan rnd: = Aleatorio
(30); dict.Remove (rnd); fin ; // elementos de bucle - ir a través de las
claves log.Lines.Add ('ELEMENTS:'); para i en dict.Keys do log.Lines.Add (Formato ('%
d,% s', [i, dict.Items [i]])); // tenemos un valor de clave "especial" si dict.TryGetValue
(80, c) luego log.Lines.Add (Formato ('Found' special ', valor:% s', [c])) else log.Lines
.Add (Formato ('clave' Especial 'no encontrada', [])); // ordenar por claves
ascendentes log.Lines.Add ('CLAVES CLASIFICADAS ASCENDING:'); sortedDictKeys: =
TList.Create (dict.Keys); prueba sortedDictKeys.Sort; // ascending
predeterminado para i en sortedDictKeys do log.Lines.Add (Formato ('% d,% s', [i,
dict.Items [i]])); finalmente sortedDictKeys.Free; fin ; // ordenar por claves
descendiendo log.Lines.Add ('CLAVES CLASIFICADAS
DESCENDIENDO:'); sortedDictKeys: = TList.Create
(dict.Keys); intente sortedDictKeys.Sort (TComparer.Construct ( función ( const L, R:
integer): entero begin result: = R -
L; end )); para i en sortedDictKeys do log.Lines.Add (Formato ('% d,% s', [i, dict.Items
[i]])); finalmente sortedDictKeys.Free; fin ; finalmente dict.Free; fin ; fin ;

• Primero, declaramos nuestro diccionario especificando cuáles serán los


tipos de TKey y TValue:

• > dict: TDictionary;

• Luego, el diccionario se completa utilizando el método Agregar. Debido a


que un diccionario no puede tener dos pares con el mismo valor de clave,
puede usar el método ContainsKey para verificar si algún par de valores
clave ya está dentro del diccionario.

• Para eliminar un par del diccionario, use el método Eliminar. Este método
no causará problemas si un par con una clave especificada no es parte del
diccionario.

• Para recorrer todos los pares haciendo un bucle a través de las teclas,
puede hacer un bucle for in .

• Use el método TryGetValue para verificar si algún par clave-valor está


incluido en el diccionario.

• Ordenar el diccionario
• Como un diccionario es una tabla hash, no almacena elementos en un
orden de clasificación definido. Para iterar a través de las claves que se
ordenan para satisfacer sus necesidades específicas, aproveche el TList,
un tipo de colección genérica que admite la ordenación.

• El código anterior ordena las teclas ascendentes y descendentes y toma los


valores como si estuvieran almacenados en el orden ordenado en el
diccionario. La clasificación descendente de valores de clave de tipo entero
usa TComparer y un método anónimo.

• Cuando las claves y los valores son del tipo TObject


• El ejemplo mencionado anteriormente es simple porque tanto la clave como
el valor son tipos simples.

• Puede tener diccionarios complejos donde tanto la clave como el valor sean
tipos "complejos" como registros u objetos.

• Aquí hay otro ejemplo:

• > escriba TMyRecord = record Name, Apellido: string end ; TMyObject


= clase (TObject) Year, Value: integer; fin ; procedure TForm2.logDblClick (Sender:
TObject); var dict: TObjectDictionary ; myR: TmyRecord; myO: TMyObject; begin dict:
= TObjectDictionary .Create ([doOwnsValues]); prueba myR.Name: =
'Zarko'; myR.Surname: = 'Gajic'; myO: = TMyObject.Create; myO.Year: =
2012; myO.Value: = 39; dict.Add (myR, myO); myR.Name: = 'Zarko'; myR.Surname: =
'?????'; si NO dict.ContainsKey (myR) then log.Lines.Add ('no
encontrado'); finalmente dict.Free; fin ; fin ;

• Aquí se usa un registro personalizado para la clave y se usa un objeto /


clase personalizado para el valor.

• Tenga en cuenta el uso de una clase


especializada TObjectDictionary aquí. TObjectDictionary puede manejar la
vida útil de los objetos automáticamente.

• El valor de clave no puede ser nulo, mientras que el valor de valor puede.

• Cuando se crea una instancia de TObjectDictionary, un parámetro de


propiedad especifica si el diccionario posee las claves, los valores o ambos,
y por lo tanto le ayuda a no tener pérdidas de memoria.

Sobrecarga del método Delphi y


parámetros predeterminados
• by Zarko Gajic
• Cómo funcionan la sobrecarga y los parámetros predeterminados en Delphi

• Las funciones y procedimientos son una parte importante del lenguaje


Delphi. Comenzando con Delphi 4, Delphi nos permite trabajar con
funciones y procedimientos que admiten parámetros predeterminados
(haciendo que los parámetros sean opcionales), y permite que dos o más
rutinas tengan un nombre idéntico pero funcionen como rutinas
completamente diferentes.

• Veamos cómo la sobrecarga y los parámetros predeterminados pueden


ayudarlo a codificar mejor.

• Sobrecarga
• En pocas palabras, la sobrecarga es declarar más de una rutina con el
mismo nombre.

• La sobrecarga nos permite tener múltiples rutinas que comparten el mismo


nombre, pero con una cantidad diferente de parámetros y tipos.

• Como ejemplo, consideremos las dos funciones siguientes:

• > {Las rutinas sobrecargadas deben declararse con la directiva de


sobrecarga} function SumAsStr (a, b:
integer): string ; sobrecarga ; comenzar Resultado: = IntToStr (a +
b); fin; función SumAsStr (a, b: extended; Dígitos:
entero): cadena ; sobrecarga ; comenzar Resultado: = FloatToStrF (a + b, ffFixed,
18, dígitos); fin ;

• Estas declaraciones crean dos funciones, ambas llamadas SumAsStr, que


toman un número diferente de parámetros y son de dos tipos diferentes.
Cuando llamamos a una rutina sobrecargada, el compilador debe poder
decir a qué rutina queremos llamar.

• Por ejemplo, SumAsStr (6, 3) llama a la primera función SumAsStr porque


sus argumentos tienen valores enteros.

• Nota: Delphi lo ayudará a elegir la implementación correcta con la ayuda de


la finalización del código y la información del código.

• Por otro lado, considere si tratamos de llamar a la función SumAsStr de la


siguiente manera:

• > SomeString: = SumAsStr (6.0,3.0)

• Obtendremos un error que dice: " no hay una versión sobrecargada de


'SumAsStr' que pueda invocarse con estos argumentos. " Esto significa que
también deberíamos incluir el parámetro Digits utilizado para especificar el
número de dígitos después del punto decimal.

• Nota: Solo hay una regla al escribir rutinas sobrecargadas, y es que una
rutina sobrecargada debe diferir en al menos un tipo de parámetro. El tipo
de devolución, en cambio, no se puede usar para distinguir entre dos
rutinas.

• Dos unidades: una rutina


• Digamos que tenemos una rutina en la unidad A, y la unidad B usa la
unidad A, pero declara una rutina con el mismo nombre. La declaración en
la unidad B no necesita la directiva de sobrecarga; debemos usar el nombre
de la unidad A para calificar las llamadas a la versión A de la rutina de la
unidad B.

• Considera algo como esto:

• > unidad B; ... usa A; ... procedimiento RoutineName; comenzar Resultado: =


A.RoutineName; fin ;

• Una alternativa al uso de rutinas sobrecargadas es usar parámetros


predeterminados, lo que generalmente resulta en menos código para
escribir y mantener.
• Parámetros predeterminados / opcionales
• Para simplificar algunas afirmaciones, podemos dar un valor por defecto
para el parámetro de una función o procedimiento, y podemos llamar a la
rutina con o sin el parámetro, haciéndolo opcional. Para proporcionar un
valor predeterminado, finalice la declaración del parámetro con el símbolo
igual (=) seguido de una expresión constante.

• Por ejemplo, dada la declaración

• > función SumAsStr (a, b: extendida; dígitos: entero = 2): cadena ;

• las siguientes llamadas a funciones son equivalentes.

• > SumAsStr (6.0, 3.0) > SumAsStr (6.0, 3.0, 2)

• Nota: Los parámetros con valores predeterminados deben aparecer al final


de la lista de parámetros y deben pasar por valor o como const. Un
parámetro de referencia (var) no puede tener un valor predeterminado.

• Al llamar rutinas con más de un parámetro predeterminado, no podemos


omitir parámetros (como en VB):

• > función SkipDefParams ( var A: string; B: integer = 5, C: boolean = False):


boolean; ... // esta llamada genera un mensaje de error CantBe: = SkipDefParams
('delphi',, True);

• Sobrecarga con parámetros predeterminados


• Al usar la sobrecarga de función o procedimiento y los parámetros
predeterminados, no introduzca declaraciones de rutina ambiguas.

• Considere las siguientes declaraciones:

• > procedimiento DoIt (A: extendido; B: entero =


0); sobrecarga ; procedimiento DoIt (A: extendido); sobrecarga ;

• La llamada al procedimiento DoIt como DoIt (5.0) no se compila.

• Debido al parámetro predeterminado en el primer procedimiento, esta


instrucción puede llamar a ambos procedimientos, porque es imposible
saber qué procedimiento se debe invocar.
Cómo agregar casillas de verificación y
botones de radio a un TTreeView
• by Zarko Gajic

El componente TTreeView Delphi (ubicado en la pestaña de la paleta del


componente "Win32") representa una ventana que muestra una lista jerárquica de
elementos, como los títulos de un documento, las entradas de un índice o los
archivos y directorios de un disco.

Nodo de árbol con casilla de verificación o botón de radio?


El TTreeview de Delphi no admite casillas de verificación de forma nativa, pero sí
el control WC_TREEVIEW subyacente. Puede agregar casillas de verificación a
la vista de árbol anulando el procedimiento CreateParams de TTreeView,
especificando el estilo de TVS_CHECKBOXES para el control (vea MSDN para
más detalles).

El resultado es que todos los nodos en la vista de árbol tendrán casillas de


verificación asociadas. Además, la propiedad StateImages ya no se puede usar
porque WC_TREEVIEW usa esta lista de imágenes internamente para
implementar casillas de verificación. Si desea alternar las casillas de verificación,
tendrá que hacer eso usando SendMessage o

TreeView_SetItem / TreeView_GetItem macros de CommCtrl.pas. El


WC_TREEVIEW solo admite casillas de verificación, no botones de opción.

El enfoque que debe descubrir en este artículo es mucho más flexible: puede tener
casillas de verificación y botones de radio mezclados con otros nodos de la forma
que desee sin cambiar el TTreeview o crear una nueva clase a partir de él para
que esto funcione. Además, usted mismo decide qué imágenes usar para las
casillas de verificación / botones de radio simplemente agregando las imágenes
adecuadas a la lista de imágenes de StateImages.

TreeNode con casilla de verificación o botón de radio


Al contrario de lo que puedas creer, esto es bastante simple de lograr en Delphi.

Estos son los pasos para hacer que funcione:

▪ Configure una lista de imágenes (componente TImageList en la pestaña de la paleta del


componente "Win32") para la propiedad TTreeview.StateImages que contiene las
imágenes para los estados marcados y sin marcar para las casillas de verificación y / o
botones de opción.
▪ Llame al procedimiento ToggleTreeViewCheckBoxes (consulte a continuación) en los
eventos OnClick y OnKeyDown de treeview. El procedimiento
ToggleTreeViewCheckBoxes altera el StateIndex del nodo seleccionado para reflejar el
estado actual marcado / no verificado.
Para que su vista de árbol sea aún más profesional, debe verificar dónde se hace
clic en un nodo antes de alternar las imágenes de estado: al solo alternar el nodo
cuando se hace clic en la imagen real, los usuarios pueden seleccionar el nodo sin
cambiar su estado.

Además, si no desea que sus usuarios expandan / colapsen la vista de árbol,


llame al procedimiento FullExpand en el evento OnShow de formularios y
establezca AllowCollapse en false en el evento OnCollapsing de la vista de árbol.

Aquí está la implementación del procedimiento ToggleTreeViewCheckBoxes:

procedure ToggleTreeViewCheckBoxes (Node: TTreeNode; cUnChecked, cChecked,


cRadioUnchecked, cRadioChecked: integer); var tmp: TTreeNode; comience si Asignado
(Nodo) luego comience si Node.StateIndex = cUnChecked then Node.StateIndex: =
cChecked else si Node.StateIndex = cChecked then Node.StateIndex: = cUnChecked else
si Node.StateIndex = cRadioUnChecked then begin tmp: = Node.Parent ; si no Asignado
(tmp) entonces tmp: = TTreeView (Node.TreeView) .Items.getFirstNode else tmp: =
tmp.getFirstChild; mientras Assigned
(tmp) comienza si (tmp.StateIndex en [cRadioUnChecked,
cRadioChecked]) then tmp.StateIndex: = cRadioUnChecked; tmp: =
tmp.getNextSibling; fin ; Node.StateIndex: = cRadioChecked; fin ; // si StateIndex =
cRadioUnChecked end ; // si Assigned (Node) end ; (* ToggleTreeViewCheckBoxes *)

Como puede ver en el código anterior, el procedimiento comienza buscando los


nodos de las casillas de verificación y simplemente activándolos o
desactivándolos. Luego, si el nodo es un botón de radio no seleccionado, el
procedimiento se mueve al primer nodo en el nivel actual, establece todos los
nodos en ese nivel en cRadioUnchecked (si son nodos cRadioUnChecked o
cRadioChecked) y finalmente alterna Node a cRadioChecked.

Observe cómo se ignoran los botones de opción ya controlados. Obviamente, esto


se debe a que un botón de radio ya verificado se alternará para desmarcarse,
dejando los nodos en un estado indefinido. Difícilmente lo que querrías la mayor
parte del tiempo.

Aquí se explica cómo hacer que el código sea aún más profesional: en el evento
OnClick de TreeView, escriba el siguiente código para alternar las casillas de
verificación solo si se hizo clic en el estado (las constantes cFlatUnCheck,
cFlatChecked, etc. se definen en otros lugares como índices en la lista de
imágenes de StateImages) :

procedure TForm1.TreeView1Click (Sender: TObject); var P:


TPoint; comenzar GetCursorPos (P); P: = TreeView1.ScreenToClient
(P); if (htOnStateIcon en TreeView1.GetHitTestInfoAt (PX,
PY)) luego ToggleTreeViewCheckBoxes (TreeView1.Selected, cFlatUnCheck, cFlatChecked,
cFlatRadioUnCheck, cFlatRadioChecked); fin ; (* TreeView1Click *)

El código obtiene la posición actual del mouse, se convierte en coordenadas de


vista en árbol y comprueba si se hizo clic en StateIcon llamando a la función
GetHitTestInfoAt. Si lo fue, se llama al procedimiento de alternar.

Principalmente, esperaría que la barra espaciadora alternase las casillas de


verificación o los botones de opción, así que aquí se explica cómo escribir el
evento TreeView OnKeyDown usando ese estándar:

procedure TForm1.TreeView1KeyDown (Sender: TObject; var Clave: Word; Shift:


TShiftState); begin if (Key = VK_SPACE) y Assigned
(TreeView1.Selected) luego ToggleTreeViewCheckBoxes (TreeView1.Selected,
cFlatUnCheck, cFlatChecked, cFlatRadioUnCheck, cFlatRadioChecked); fin; (*
TreeView1KeyDown *)

Finalmente, así es como podrían verse los eventos OnShow y TreeView


OnChanging del formulario si desea evitar el colapso de los nodos de treeview:

procedure TForm1.FormCreate (Sender: TObject); comenzar TreeView1.FullExpand; fin ; (*


FormCreate *) procedure TForm1.TreeView1Collapsing (Sender: TObject; Node:
TTreeNode; var AllowCollapse: Boolean); begin AllowCollapse: = falso; fin ; (*
TreeView1Collapsing *)

Finalmente, para verificar si un nodo está marcado, simplemente haga la siguiente


comparación (en el controlador de eventos OnClick de Button, por ejemplo):

procedure TForm1.Button1Click (Sender: TObject); var BoolResult: boolean; tn:


TTreeNode; comience si Asignado (TreeView1.Selected) luego comience tn: =
TreeView1.Selected; BoolResult: = tn.StateIndex en [cFlatChecked, cFlatRadioChecked];
Memo1.Text: = tn.Text + # 13 # 10 + 'Seleccionado:' + BoolToStr (BoolResult,
True); fin ; fin ; (* Button1Click *)

Aunque este tipo de codificación no se puede considerar de misión crítica, puede


dar a sus aplicaciones un aspecto más profesional y más suave. Además, al usar
juiciosamente las casillas de verificación y los botones de radio, pueden hacer que
su aplicación sea más fácil de usar. ¡Seguro que se verán bien!

Esta imagen a continuación fue tomada de una aplicación de prueba utilizando el


código descrito en este artículo. Como puede ver, puede mezclar libremente
nodos con casillas de verificación o botones de radio con los que no tienen
ninguno, aunque no debe mezclar nodos "vacíos" con nodos de " casilla " (mire los
botones de opción de la imagen) ya que hace que sea muy difícil ver qué nodos
están relacionados.
TForm.Create (AOwner)
• by Zarko Gajic

Escogiendo el parámetro correcto para optimizar el uso de la memoria

Cuando crea objetos Delphi dinámicamente que heredan de TControl, como un


TForm (que representa una forma / ventana en aplicaciones Delphi), el constructor
"Crear" espera un parámetro "Propietario":

> constructor Create (AOwner: TComponent);

El parámetro AOwner es el propietario del objeto TForm. El propietario del


formulario es responsable de liberar el formulario, es decir, la memoria asignada
por el formulario, cuando sea necesario.

El formulario aparece en la matriz Componentes de su propietario y se destruye


automáticamente cuando se destruye su propietario.

Tiene tres opciones para el parámetro AOwner: Nil , self y aplicación .

Para entender la respuesta, primero necesita saber el significado de "nil", "self" y


"Application".

▪ Nil especifica que ningún objeto posee el formulario y, por lo tanto, el


desarrollador es responsable de liberar el formulario creado (llamando a
myForm.Free cuando ya no necesita el formulario)
▪ Self especifica el objeto en el que se llama el método. Si, por ejemplo, está
creando una nueva instancia de un formulario TMyForm desde el controlador
OnClick de un botón (donde este botón se coloca en un MainForm), self
se refiere a "MainForm". Por lo tanto, cuando MainForm se libera, también
libera MyForm.
▪ La aplicación especifica una variable de tipo de TApplication global creada
cuando ejecuta su aplicación. La "aplicación" encapsula su aplicación y
proporciona muchas funciones que ocurren en el fondo del programa.
Ejemplos:

1. Formas modales Cuando crea un formulario para mostrarlo modalmente y lo


libera cuando el usuario cierra el formulario, use "nil" como propietario: var
myForm: TMyForm; begin myForm: = TMyForm.Create ( nil ); prueba
myForm.ShowModal; finalmente myForm.Free; fin; fin;
2. Formas sin formas. Use "Aplicación" como propietario:
var
myForm: TMyForm;
...
myForm: = TMyForm.Create (Aplicación);

Ahora, cuando finalice (salga) la aplicación, el objeto "Aplicación" liberará la


instancia "myForm".

¿Por qué y cuándo NO se recomienda TMyForm.Create (Application)? Si el


formulario es un formulario modal y se destruirá, debe pasar "nil" para el
propietario.

Puede pasar "solicitud", pero el retraso causado por el método de notificación que
se envía a cada componente y forma propiedad de la Aplicación o indirectamente
puede ser perjudicial. Si su aplicación consta de muchos formularios con muchos
componentes (en miles) y el formulario que está creando tiene muchos controles
(en cientos), el retraso en la notificación puede ser significativo.

Pasar "nil" como el propietario en lugar de "solicitud" hará que el formulario


aparezca antes, y de lo contrario no afectará el código.

Sin embargo, si el formulario que necesita crear no es modal y no se crea desde el


formulario principal de la aplicación, cuando se especifica "self" como propietario,
al cerrar el propietario se liberará el formulario creado. Use "self" cuando no quiera
que el formulario sobreviva a su creador.

Advertencia : Para instanciar dinámicamente un componente Delphi y liberarlo


explícitamente en algún momento posterior, siempre pase "nil" como propietario.
De lo contrario, se pueden presentar riesgos innecesarios, así como problemas de
rendimiento y de mantenimiento del código.

En las aplicaciones SDI, cuando un usuario cierra el formulario (haciendo clic en el


botón [x]), el formulario todavía existe en la memoria: solo se oculta. En
aplicaciones MDI, cerrar un formulario MDI secundario solo lo minimiza.
El evento OnClose proporciona un parámetro de acción (del tipo TCloseAction)
que puede usar para especificar qué sucede cuando un usuario intenta cerrar el
formulario. Establecer este parámetro en "caFree" liberará el formulario.

¡La línea de código más libre de errores es la que no tiene que escribir!

Desafortunadamente, la construcción de aplicaciones incluye codificación.


Independientemente de cuán cuidadosamente escriba / depure su programa, será
imposible imaginar cada situación que pueda salir mal. El usuario inexperto podría,
por ejemplo, intentar abrir un archivo inexistente o ingresar un valor incorrecto en
un campo de datos.
Los usuarios cometen errores y debemos estar preparados para manejar /
prevenir estos errores donde sea y cuando sea posible.

Errores, Excepciones?

Una excepción generalmente es una condición de error u otro evento que


interrumpe el flujo normal de ejecución en una aplicación. Cuando se produce un
error al procesar una línea de código, Delphi crea (aumenta) un descendiente de
objeto de TObject llamado objeto de excepción.

Bloques guardados

Una aplicación responde a una excepción ejecutando un código de terminación,


manejando la excepción o ambas. La forma de habilitar la captura de error /
excepción dentro de un código dado, la excepción debe ocurrir dentro de un
bloque de instrucciones oculto. El código general se ve así:

> prueba {bloque de código guardado} excepto en do begin {exception block-


handleles SomeException} end; fin;
Una instrucción try / except ejecuta las instrucciones en el bloque de código
protegido. Si las instrucciones se ejecutan sin que se genere ninguna excepción,
se ignora el bloque de excepción y el control pasa a la instrucción que sigue a la
palabra clave final.

Ejemplo:

> ... Cero: = 0; try dummy: = 10 / Zero; excepto en EZeroDivide do MessageDlg ('No
se puede dividir por cero!', mtError, [mbOK], 0); fin; ...

Protección de recursos

Cuando una sección de código adquiere un recurso, a menudo es necesario


garantizar que el recurso se libera nuevamente (o puede tener una fuga de
memoria ), independientemente de si el código se completa normalmente o si se
interrumpe con una excepción.

En este caso, la sintaxis utiliza finalmente la palabra clave y se ve así:

> {algún código para asignar recursos} intente {bloque de código guardado}
finalmente {bloque de terminación - código para liberar recursos} final;
Ejemplo:
> ... AboutBox: = TAboutBox.Create (nil); prueba AboutBox.ShowModal; finalmente
AboutBox.Release; fin; ...

Application.OnException

Si su aplicación no maneja el error que causó la excepción, Delphi usará su


manejador de excepción predeterminado: aparecerá un cuadro de mensaje.
Puede considerar escribir código en el evento OnException para el objeto
TApplication, para atrapar errores en el nivel de la aplicación.

Break On Exceptions

Al crear un programa con manejo de excepciones, es posible que no desee que


Delphi incumpla las Excepciones. Esta es una gran característica si desea que
Delphi muestre dónde se ha producido una excepción; sin embargo, puede ser
molesto cuando prueba su propio manejo de excepciones.

Pocas palabras finales

La idea de este artículo es darle una rápida mirada a las excepciones. Para una
discusión más detallada sobre el manejo de excepciones, considere el Manejo de
excepciones en el manejo de excepciones de Delphi , usando una herramienta
como Delphi Crash / Exception Handling con Bug Reporting y algunos de los
siguientes artículos relacionados:

Dónde encontrar glifos e iconos para una


aplicación de Delphi, menú, barra de
herramientas
• by Zarko Gajic
• Interfaz de usuario profesional y única

• Un glifo en Delphi lingo es una imagen de mapa de bits que puede


mostrarse en controles BitBtn o SpeedButton utilizando la propiedad Glyph
del control.

• Los glifos e íconos (y los gráficos en general) hacen que los elementos de
la interfaz de usuario de la aplicación se vean profesionales y únicos.

• Los controles Delphi y VCL le permiten configurar fácilmente barras de


herramientas, menús y otros elementos de la interfaz de usuario con
gráficos personalizados.
• Bibliotecas de iconos y glifo para aplicaciones Delphi
• Cuando instala Delphi , por diseño también se instalan dos bibliotecas de
imágenes.

• El mapa de bits y los íconos de Delphi "estándar" se pueden ubicar en la


carpeta " Archivos de programa \ Archivos comunes \ CodeGear Shared \
Images" y un conjunto de terceros de GlyFx.

• El paquete GlyFX contiene una gran cantidad de íconos seleccionados de


muchos de los conjuntos de iconos de acciones de GlyFx, así como
imágenes y animaciones de asistentes. Los iconos se suministran en varios
tamaños y formatos (pero no todos los tamaños y formatos están incluidos
para todos los iconos).

• El paquete GlyFx se puede encontrar en la carpeta "\ Archivos de programa


\ Archivos comunes \ CodeGear Shared \ Images \ GlyFX".

Cómo crear, usar y cerrar formularios en


Delphi
• by Zarko Gajic

Comprender el ciclo de vida de un formulario de Delphi

En Windows, la mayoría de los elementos de la interfaz de usuario son ventanas.


En Delphi , cada proyecto tiene al menos una ventana: la ventana principal del
programa. Todas las ventanas de una aplicación Delphi se basan en objetos
TForm.

Formar
Los objetos de formulario son los componentes básicos de una aplicación Delphi,
las ventanas reales con las que un usuario interactúa cuando ejecuta la aplicación.
Los formularios tienen sus propias propiedades, eventos y métodos con los que
puede controlar su apariencia y comportamiento.

Un formulario es en realidad un componente Delphi, pero a diferencia de otros


componentes, un formulario no aparece en la paleta de componentes.

Normalmente creamos un objeto de formulario iniciando una nueva aplicación


(Archivo | Nueva Aplicación). Esta forma recién creada será, por defecto, la forma
principal de la aplicación, la primera forma creada en tiempo de ejecución.

Nota: Para agregar un formulario adicional al proyecto Delphi, seleccionamos


Archivo | Nuevo formulario. Hay, por supuesto, otras formas de agregar un
formulario "nuevo" a un proyecto Delphi.
Nacimiento
OnCreate
El evento OnCreate se activa cuando se crea un TForm por primera vez, es decir,
solo una vez. La declaración responsable de crear el formulario está en el origen
del proyecto (si el proyecto lo configura automáticamente). Cuando se está
creando un formulario y su propiedad Visible es Verdadero, los siguientes eventos
ocurren en el orden indicado: OnCreate, OnShow, OnActivate, OnPaint.

Debe usar el controlador de eventos OnCreate para hacer, por ejemplo, tareas de
inicialización como la asignación de listas de cadenas.

Cualquier objeto creado en el evento OnCreate debe ser liberado por el evento
OnDestroy.

> OnCreate -> OnShow -> OnActivate -> OnPaint -> OnResize -> OnPaint ...

En el programa
Este evento indica que se está mostrando el formulario. Se llama a OnShow justo
antes de que un formulario sea visible. Además de las formas principales, este
evento ocurre cuando establecemos la propiedad Visible de los formularios en
True, o llamamos al método Show o ShowModal.

Activado
Se llama a este evento cuando el programa activa el formulario, es decir, cuando
el formulario recibe el foco de entrada. Use este evento para cambiar qué control
realmente obtiene el foco si no es el deseado.

OnPaint, OnResize
Eventos como OnPaint y OnResize siempre se llaman después de que se crea el
formulario inicialmente, pero también se llaman repetidamente. OnPaint ocurre
antes de que se pinten los controles del formulario (úselo para una pintura
especial en el formulario).

Vida
Como hemos visto, el nacimiento de una forma no es tan interesante como
pueden ser la vida y la muerte. Cuando se crea su formulario y todos los controles
están esperando que los eventos lo manejen, ¡el programa se ejecuta hasta que
alguien intente cerrar el formulario!

Muerte
Una aplicación controlada por eventos deja de ejecutarse cuando todas sus
formas están cerradas y no se está ejecutando ningún código. Si aún existe un
formulario oculto cuando se cierra el último formulario visible, parecerá que su
aplicación ha finalizado (porque no hay formularios visibles), pero de hecho
continuará ejecutándose hasta que se cierren todos los formularios ocultos. Solo
piense en una situación donde la forma principal se oculta temprano y todas las
otras formas están cerradas.
> ... OnCloseQuery -> OnClose -> OnDeactivate -> OnHide -> OnDestroy

OnCloseQuery
Cuando tratamos de cerrar el formulario usando el método Close o por otros
medios (Alt + F4), se llama al evento OnCloseQuery.

Por lo tanto, el controlador de eventos para este evento es el lugar para interceptar
el cierre de un formulario y evitarlo. Usamos OnCloseQuery para preguntar a los
usuarios si están seguros de que realmente desean que el formulario se cierre.

> procedure TForm1.FormCloseQuery (Sender: TObject; var CanClose:


Boolean); comience si MessageDlg ('¿Cerrar realmente esta ventana?', mtConfirmation,
[mbOk, mbCancel], 0) = mrCancel luego CanClose: = False; fin ;

Un controlador de eventos OnCloseQuery contiene una variable CanClose que


determina si un formulario puede cerrarse. El controlador de eventos
OnCloseQuery puede establecer el valor de CloseQuery en False (a través del
parámetro CanClose), anulando así el método Close.

OnClose
Si OnCloseQuery indica que el formulario debe cerrarse, se llama al evento
OnClose.

El evento OnClose nos da una última oportunidad para evitar que se cierre el
formulario.

El controlador de eventos OnClose tiene un parámetro de acción, con los


siguientes cuatro valores posibles:

▪ caNone . El formulario no puede cerrarse. Como si hubiéramos configurado CanClose


en False en OnCloseQuery.
▪ caHide . En lugar de cerrar el formulario, lo ocultas.
▪ caFree . El formulario está cerrado, por lo que Delphi libera la memoria asignada.
▪ caminizar La forma es minimizada, en lugar de cerrada. Esta es la acción
predeterminada para formularios secundarios MDI. Nota: Cuando un usuario apaga
Windows, el evento OnCloseQuery se activa, no OnClose. Si desea evitar que Windows
se cierre, coloque su código en el controlador de eventos OnCloseQuery, por supuesto
CanClose = False no servirá.
OnDestroy
Después de que se haya procesado el método OnClose y se cierre el formulario,
se llama al evento OnDestroy. Utilice este evento para operaciones opuestas a las
del evento OnCreate. Por lo tanto, OnDestroy se usa para desasignar objetos
relacionados con el formulario y liberar la memoria correspondiente.
Por supuesto, cuando se cierra el
formulario principal para un proyecto,
la aArrastre un formulario de Delphi sin
la barra de título
• by Zarko Gajic

La forma más común de mover una ventana es arrastrándola por su barra de


título. Siga leyendo para descubrir cómo puede proporcionar capacidades de
arrastre para los formularios Delph i sin una barra de título, de modo que el
usuario puede mover un formulario haciendo clic en cualquier lugar del área del
cliente.

Por ejemplo, considere el caso de una aplicación de Windows que no tiene una
barra de título, ¿cómo podemos mover dicha ventana? De hecho, es posible crear
ventanas con una barra de título no estándar e incluso formas no rectangulares.

En este caso, ¿cómo podría Windows saber dónde están los bordes y las
esquinas de la ventana?

El mensaje WM_NCHitTest de Windows


El sistema operativo Windows se basa principalmente en el manejo de mensajes .
Por ejemplo, cuando hace clic en una ventana o un control, Windows le envía un
mensaje wm_LButtonDown, con información adicional sobre dónde está el cursor
del mouse y qué teclas de control están presionadas actualmente. ¿Suena
familiar? Sí, esto no es más que un evento OnMouseDown en Delphi.

Del mismo modo, Windows envía un mensaje wm_NCHitTest cada vez que
se produce un evento de mouse , es decir, cuando se mueve el cursor, o cuando
se presiona o se suelta un botón del mouse.

Si podemos hacer que Windows piense que el usuario está arrastrando (ha hecho
clic) en la barra de título en lugar de en el área del cliente, entonces el usuario
puede arrastrar la ventana haciendo clic en el área del cliente. La forma más fácil
de hacerlo es "engañar" a Windows para que piense que realmente está haciendo
clic en la barra de título de un formulario.

Esto es lo que tienes que hacer:

1. Inserta la siguiente línea en la sección "Declaraciones privadas" de tu formulario


(declaración del procedimiento de manejo de mensajes):

> procedimiento WMNCHitTest ( var Msg: TWMNCHitTest); mensaje WM_NCHitTest;


2. Agregue el siguiente código en la sección "implementación" de la unidad de su
formulario (donde Form1 es el nombre del formulario asumido):

> procedimiento TForm1.WMNCHitTest ( var Msg:


TWMNCHitTest); comenzar heredado ; si Msg.Result = htClient entonces Msg.Result: =
htCaption; fin ;

La primera línea de código en el controlador de mensajes llama al método


heredado para obtener el tratamiento predeterminado para el mensaje
wm_NCHitTest. La parte If en el procedimiento intercepta y cambia el
comportamiento de su ventana. Esto es lo que realmente ocurre: cuando el
sistema operativo envía un mensaje wm_NCHitTest a la ventana, junto con las
coordenadas del mouse, la ventana devuelve un código que indica qué porción de
sí mismo ha sido golpeada. La información importante, para nuestra tarea, está en
el valor del campo Resultados Msg. En este punto, tenemos la oportunidad de
modificar el resultado del mensaje.

Esto es lo que hacemos: si el usuario ha hecho clic en el área de cliente del


formulario, hacemos que Windows piense que el usuario hizo clic en la barra de
título. En "palabras" de Object Pascal : si el valor de retorno del mensaje es
HTCLIENT, simplemente lo cambiamos a HTCAPTION.

No más eventos de mouse


Al cambiar el comportamiento predeterminado de nuestros formularios,
eliminamos la capacidad de Windows para notificarlo cuando el mouse está sobre
el área del cliente. Un efecto secundario de este truco es que su formulario ya no
generará eventos para los mensajes del mouse .

Ventana Sin Bordes Sin Capítulos


Si desea una ventana sin márgenes sin título similar a una barra de herramientas
flotante, establezca el Título del formulario en una cadena vacía, desactive todas
las BorderIcons y establezca BorderStyle en bsNone.

Un formulario se puede cambiar de varias formas mediante la aplicación de código


personalizado en el método CreateParams.

Más trucos de WM_NCHitTest


Si observa más detenidamente el mensaje wm_NCHitTest, verá que el valor de
retorno de la función indica la posición del punto caliente del cursor. Esto nos
permite jugar un poco más con el mensaje para crear resultados extraños.

El siguiente fragmento de código evitará que los usuarios cierren sus formularios
haciendo clic en el botón Cerrar.

> si Msg.Result = htClose entonces Msg.Result: = htNowhere;


Si el usuario está tratando de mover el formulario haciendo clic en la barra de título
y arrastrando, el código reemplaza el resultado del mensaje con un resultado que
indica que el usuario hizo clic en el área del cliente.

Esto evita que el usuario mueva la ventana con el mouse (al contrario de lo que
estábamos haciendo al principio del artículo).

> si Msg.Result = htCaption entonces Msg.Result: = htClient;

Tener componentes en un formulario


En la mayoría de los casos, tendremos algunos componentes en un formulario.
Digamos, por ejemplo, que un objeto del Panel está en un formulario. Si la
propiedad Align de un panel está configurada como alClient, el Panel llena toda el
área del cliente de modo que es imposible seleccionar el formulario principal
haciendo clic en él. El código anterior no funcionará, ¿por qué? Es porque el
mouse siempre se mueve sobre el componente del Panel, no el formulario.

Para mover nuestro formulario arrastrando un panel en el formulario, debemos


agregar algunas líneas de código en el procedimiento de evento OnMouseDown
para el componente Panel:

> procedure TForm1.Panel1MouseDown (Sender: TObject; Botón: TMouseButton; Shift:


TShiftState; X, Y: Integer); comenzar ReleaseCapture; SendMessage (Form1.Handle,
WM_SYSCOMMAND, 61458, 0); fin ;

Nota: este código no funcionará con controles que no sean de ventana, como
los componentes de TLabel .

Creación y uso de archivos DLL de Delphi


• by Zarko Gajic
• Introducción a las DLL de Delphi

• Una biblioteca de vínculos dinámicos (DLL) es una colección de rutinas


(pequeños programas) a las que las aplicaciones y otras DLL pueden
llamar. Como las unidades, contienen código o recursos que se pueden
compartir entre varias aplicaciones.

• El concepto de DLL es el núcleo del diseño arquitectónico de Windows, y


en su mayor parte, Windows es simplemente una colección de DLL.

• Con Delphi, puede escribir y usar sus propias DLL e incluso llamar
funciones independientemente de si fueron desarrolladas o no con otros
sistemas o desarrolladores, como Visual Basic o C / C ++.
• Crear una biblioteca de enlace dinámico
• Las siguientes líneas demostrarán cómo crear una DLL simple usando
Delphi.

• Para comenzar, inicie Delphi y vaya a Archivo> Nuevo> DLL para compilar
una nueva plantilla DLL. Seleccione el texto predeterminado y reemplácelo
con esto:

• > biblioteca TestLibrary; usa SysUtils, Classes,


Dialogs; procedimiento DllMessage; exportar ; comience ShowMessage ('Hola
mundo desde una DLL de Delphi'); fin ; exporta DllMessage; comenzar fin

• Si miras el archivo de proyecto de cualquier aplicación Delphi, verás que


comienza con el programa de palabra reservada. Por el contrario, las DLL
siempre comienzan con la biblioteca y luego una cláusula de uso para
cualquier unidad. En este ejemplo, sigue el procedimiento de DllMessage ,
que no hace nada más que mostrar un mensaje simple.

• Al final del código fuente hay una declaración de exportación que enumera
las rutinas que en realidad se exportan de la DLL de forma que otra
aplicación pueda llamarlas.

• Lo que esto significa es que puede tener, por ejemplo, cinco procedimientos
en un archivo DLL y solo dos de ellos (enumerados en la sección
de exportaciones ) se pueden llamar desde un programa externo (los tres
restantes son "procedimientos secundarios").

• Para usar esta DLL, debemos compilarla presionando Ctrl + F9 . Esto


debería crear una DLL llamada SimpleMessageDLL.DLL en su carpeta de
proyectos.

• Finalmente, echemos un vistazo a cómo llamar al procedimiento


DllMessage desde una DLL cargada estáticamente.

• Para importar un procedimiento contenido en una DLL, puede usar la


palabra clave external en la declaración del procedimiento. Por ejemplo,
dado el procedimiento DllMessage mostrado anteriormente, la declaración
en la aplicación de llamada se vería así:

• > procedimiento DllMessage; externo 'SimpleMessageDLL.dll'

• La llamada real a un procedimiento no es más que:

• > DllMessage;

• El código completo para un formulario Delphi (nombre: Form1 ), con un


TButton (llamado Button1 ) que llama a la función DLLMessage, se ve más
o menos así:
• > unidad Unidad1; la interfaz usa Windows, Mensajes, SysUtils, Variantes, Clases,
Gráficos, Controles, Formularios, Diálogos, StdCtrls; tipo TForm1 = clase (TForm)
Button1: TButton; procedimiento Button1Click (Sender:
TObject); privado {Declaraciones privadas} público {Declaraciones
públicas} final ; var Form1: TForm1; procedimiento DllMessage; proceso
de implementación externo 'SimpleMessageDLL.dll' {$ R *
.dfm} TForm1.Button1Click (Sender: TObject); comenzar DllMessage; fin ; fin

• Más información sobre el uso de archivos DLL en Delphi


• Para obtener más información sobre cómo crear y usar las bibliotecas de
vínculos dinámicos de Delphi, consulte estas sugerencias, trucos y técnicas
de programación de DLL.

Procesamiento de mouse avanzado


• by Zarko Gajic
• Es Presente, Entrar, Mover, Salir, Detener, Establecer, Mover, Entrar,
Sobre, Salir, Restringir ...

• Hemos aprendido cómo manejar algunos eventos básicos del mouse como
MouseUp / MouseDown y MouseMove. Sin embargo, hay momentos en los
que desea que su mouse haga lo que le dice.

• Cosas API 'Básicas'


• Muchos de nosotros escribimos programas que están diseñados para
funcionar solo con el mouse. Si estamos escribiendo programas que
requieren presencia de mouse y / o dependen del mouse, debemos
asegurarnos de que se configuren varias cosas de la manera correcta.

• ¿Está el ratón presente?


• La forma más rápida de ver si el mouse está presente:

• > procedure TForm1.FormCreate (Sender: TObject); comenzar si GetSystemMetrics


(SM_MOUSEPRESENT) <> 0 luego ShowMessage ('Mouse
presente') else ShowMessage ('Mouse NOT presente'); fin ;

• Cursor animado del ratón


• Aquí se explica cómo usar cursores animados (o incluso cómo usar un BMP
como CUR):

• > procedure TForm1.Button1Click (Sender: TObject); const MyCursor =


1; inicie Screen.Cursors [MyCursor]: = LoadCursorFromFile ('c: \ windows \ cursors \
globe.ani'); Form1.Cursor: = MyCursor; fin ;
• Posicionando el mouse
• La función de API SetCursorPos mueve el cursor a las coordenadas de
pantalla especificadas. Como esta función no tiene un identificador de
ventana como parámetro, x / y tiene que ser coordenadas de pantalla. Su
componente utiliza coordenadas relativas, por ejemplo, relativas a un
TForm. Debe usar la función ClientToScreen para calcular las coordenadas
de pantalla adecuadas.

• > procedimiento SetMousePos (x, y: longint); var pt: TPoint; begin pt: =
ClientToScreen (point (x, y)); SetCursorPos (pt.x, pt.y); fin ;

• Simulaciones
• En la mayoría de las ocasiones, queremos que el mouse se mueva a una
posición determinada en la pantalla. Sabemos que algunos componentes
no responden a un cambio de cursor hasta que el usuario mueva el mouse,
tenemos que proporcionar una pequeña técnica para mover desde el
código.

• ¿Y qué ocurre con los clics del mouse de simulación sin llamar al
controlador de eventos OnClick?

• > procedure TForm1.Button1Click (Sender: TObject); var pt:


TPoint; comenzar Application.ProcessMessages; Screen.Cursor: =
crHourglass; GetCursorPos (pt); SetCursorPos (pt.x + 1, pt.y +
1); Application.ProcessMessages; SetCursorPos (pt.x - 1, pt.y - 1); Screen.Cursor: =
crArrow end ;

• El siguiente ejemplo simulará el evento de clic del mouse en Button2


después de hacer clic en Button1. Tenemos que usar la llamada a la API
mouse_event (). La función mouse_event sintetiza el movimiento del mouse
y los clics del botón. Las coordenadas del mouse se encuentran en
"Mickeys", donde hay 65535 "Mickeys" al ancho de una pantalla.

• > // simulando el clic del mouse // necesitamos 2 botones en el procedimiento


de formulario TForm1.Button1Click (Sender: TObject); var Pt:
TPoint; comenzar Application.ProcessMessages; {Obtener el punto en el centro del
Botón 2} Pt.x: = Button2.Left + (Button2.Width div 2); Pt.y: = Button2.Top +
(Button2.Height div 2); {Convertir Pt en coordenadas de pantalla y Mickeys} Pt: =
ClientToScreen (Pt); Pt.x: = Redondo (Pt.x * (65535 / Ancho de Pantalla)); Pt.y: =
Redondo (Pt.y * (65535 / Screen.Height)); {Simular el movimiento del
mouse} Mouse_Event (MOUSEEVENTF_ABSOLUTE o MOUSEEVENTF_MOVE, Pt.x, Pt.y,
0, 0); {Simular el botón izquierdo del mouse} Evento del mouse
(MOUSEEVENTF_ABSOLUTE o MOUSEEVENTF_LEFTDOWN, Pt.x, Pt.y, 0, 0) ;; {Simular
el botón izquierdo del mouse hacia arriba} Mouse_Event (MOUSEEVENTF_ABSOLUTE
o MOUSEEVENTF_LEFTUP, Pt.x, Pt.y, 0, 0) ;; fin ;
• Restrinja el movimiento del mouse
• Utilizando la función API de Windows ClipCursor, es posible restringir el
movimiento del mouse a una región rectangular específica en la pantalla:

• > procedure TForm1.FormCreate (Sender: TObject); var r: TRect; begin // sería una
buena idea mover el // mouse dentro del formulario antes de la restricción r: =
BoundsRect; ClipCursor (@R); fin ; procedure TForm1.FormClick (Sender:
TObject); begin // siempre asegúrese de liberar el cursor ClipCursor (nil); fin ;

• Mouse Enter, Mouse Leave?


• La detección de ingresar y salir del puntero del mouse sobre un
componente a menudo surge cuando se escribe su propio componente.
Todos los descendientes de TComponent envían un mensaje
CM_MOUSEENTER y CM_MOUSELEAVE cuando el mouse entra y sale
de los límites del componente. Tendrá que escribir un controlador de
mensajes para los respectivos mensajes si deseamos responderlos.

Cómo utiliza Delphi los archivos de


recursos
• by Zarko Gajic

Desde mapas de bits hasta iconos, pasando por cursores hasta tablas de
cadenas, cada programa de Windows usa recursos. Los recursos son aquellos
elementos de un programa que admiten el programa pero que no son código
ejecutable. En este artículo, veremos algunos ejemplos del uso de bitmaps, iconos
y cursores de los recursos.

Ubicación de los recursos

Colocar recursos en el archivo .exe tiene dos ventajas principales:

▪ Se puede acceder a los recursos más rápidamente porque lleva menos tiempo
localizar un recurso en el archivo ejecutable que cargarlo desde un archivo de
disco.

▪ El archivo de programa y los recursos pueden estar contenidos en una sola


unidad (el archivo .exe) sin la necesidad de una gran cantidad de archivos de
respaldo.

El editor de imágenes
Primero que nada, necesitamos crear un archivo de recursos. La extensión
predeterminada para los archivos de recursos es .RES . Los archivos de recursos
se pueden crear con Delphi's Image Editor .

Puede asignarle al archivo de recursos todo lo que desee, siempre que tenga la
extensión ".RES" y el nombre del archivo sin la extensión no sea el mismo que el
de cualquier unidad o proyecto. Esto es importante porque, de forma
predeterminada, cada proyecto Delphi que se compila en una aplicación tiene un
archivo de recursos con el mismo nombre que el archivo del proyecto, pero con la
extensión ".RES". Lo mejor es guardar el archivo en el mismo directorio que su
archivo de proyecto.

Incluyendo recursos en aplicaciones

Para acceder a nuestro propio archivo de recursos, debemos decirle a Delphi que
vincule nuestro archivo de recursos con nuestra aplicación. Esto se logra
agregando una directiva de compilación al código fuente.

Esta directiva debe seguir inmediatamente la directiva de formulario, como la


siguiente:

{$ R * .DFM} {$ R DPABOUT.RES}
No borre accidentalmente la parte {$ R * .DFM}, ya que esta es la línea de código
que le dice a Delphi que se vincule en la parte visual del formulario. Cuando elige
bitmaps para botones de velocidad, componentes de imagen o componentes de
botón, Delphi incluye el archivo de mapa de bits que eligió como parte del recurso
del formulario.

Delphi aísla los elementos de su interfaz de usuario en el archivo .DFM.

Para utilizar realmente el recurso, debe hacer algunas llamadas a la API de


Windows . Los mapas de bits, los cursores y los íconos almacenados en los
archivos RES pueden recuperarse utilizando las funciones
API LoadBitmap , LoadCursor y LoadIcon, respectivamente.

Fotos en Recursos

El primer ejemplo muestra cómo cargar un mapa de bits almacenado como un


recurso y mostrarlo en un componente TImage .

procedimiento TfrMain.btnCanvasPic (Sender: TObject); var bBitmap:


TBitmap; begin bBitmap: = TBitmap.Create; prueba bBitmap.Handle: = LoadBitmap
(hInstance, 'ATHENA'); Image1.Width: = bBitmap.Width; Image1.Height: =
bBitmap.Height; Image1.Canvas.Draw (0,0,
bBitmap); finalmente bBitmap.Free; fin ; fin ;
Nota: Si el mapa de bits que se va a cargar no está en el archivo de recursos, el
programa seguirá ejecutándose, simplemente no mostrará el mapa de bits. Esta
situación puede evitarse probando si el bBitmap.Handle es cero después de una
llamada a LoadBitmap () y sigue los pasos apropiados. La parte try / finally del
código anterior no resuelve este problema, solo está aquí para asegurarse de que
se destruye bbitmap y se libera su memoria asociada.

Otra forma que podemos usar para mostrar un mapa de bits desde un recurso es
la siguiente:

procedimiento TfrMain.btnLoadPicClick (Sender: TObject); Comience


Image1.Picture.Bitmap. LoadFromResourceName (hInstance, 'EARTH'); fin ;

Cursores en recursos

Screen.Cursors [] es una matriz de cursores suministrados por Delphi. Mediante el


uso de archivos de recursos, podemos agregar cursores personalizados a la
propiedad Cursores. A menos que deseamos reemplazar cualquiera de los valores
predeterminados, la mejor estrategia es usar números de cursor comenzando
desde 1.

procedimiento TfrMain.btnUseCursorClick (Sender: TObject); const NewCursor =


1; begin Screen.Cursors [NewCursor]: = LoadCursor (hInstance, 'CURHAND');
Image1.Cursor: = NewCursor; fin ;

Iconos en Recursos

Si miramos las configuraciones de Proyecto-Opciones-Aplicación de Delphi,


podemos encontrar que Delphi proporciona el icono predeterminado para un
proyecto. Este ícono representa la aplicación en el Explorador de Windows y
cuando la aplicación está minimizada.

Podemos cambiar esto fácilmente haciendo clic en el botón 'Cargar ícono'.

Si queremos, por ejemplo, animar el ícono del programa cuando el programa está
minimizado, entonces el siguiente código hará el trabajo.

Para la animación, necesitamos un componente TTimer en un formulario. El


código carga dos iconos del archivo de recursos en una matriz de objetos TIcon ;
esta matriz debe declararse en la parte pública de la forma principal. También
necesitaremos NrIco , que es una variable de tipo Integer , declarada en la
parte pública . El NrIco se utiliza para realizar un seguimiento del siguiente icono
para mostrar.

public nrIco: Integer; MinIcon: matriz [0..1] de TIcon;


... procedimiento TfrMain.FormCreate (Sender: TObject); begin MinIcon [0]: =
TIcon.Create; MinIcon [1]: = TIcon.Create; MinIcon [0] .Handle: = LoadIcon
(hInstance, 'ICOOK'); MinIcon [1] .Handle: = LoadIcon (hInstance, 'ICOFOLD'); NrIco:
= 0; Timer1.Interval: = 200; fin ; ... procedimiento TfrMain.Timer1Timer (Sender:
TObject); comience si IsIconic (Application.Handle) luego comience NrIco: =
(NrIco + 1) mod 2; Application.Icon: = MinIcon [NrIco]; fin ; fin ;
... procedimiento TfrMain.FormDestroy (Sender: TObject); comenzar MinIcon [0]
.Free; MinIcon [1] .Free; fin ;
En el controlador de eventos Timer1.OnTimer , la función IsMinimized se usa para
ver si necesitamos animar nuestro icono principal o no. Una mejor forma de lograr
esto sería capturar los botones maximizar / minimizar y actuar.

Ultimas palabras

Podemos colocar cualquier cosa (bueno, no todo) en los archivos de recursos.


Este artículo le ha mostrado cómo usar los recursos para usar / visualizar mapa de
bits, cursor o un ícono en su aplicación Delphi.

Nota: Cuando guardamos un proyecto Delphi en el disco, Delphi crea


automáticamente un archivo .RES que tiene el mismo nombre que el proyecto (si
nada más, el icono principal del proyecto está dentro). Aunque podemos alterar
este archivo de recursos, esto no es aconsejable.

Cómo mostrar sugerencias de elementos


de menú
• by Zarko Gajic
• Cuando un mouse está sobre un componente (un TButton, por ejemplo) si
la propiedad ShowHint es True y hay algún texto en la propiedad Hint , se
mostrará la ventana de sugerencia / información sobre herramientas para el
componente.

• Sugerencias para los elementos de menú?


• Con el diseño (de Windows), incluso si establece el valor de la propiedad
Sugerencia en un elemento de menú, no se mostrará la sugerencia
emergente.
Sin embargo, los elementos del menú Inicio de Windows muestran
sugerencias, y el menú Favoritos en Internet Explorer también muestra
sugerencias de elementos de menú.

• Es bastante común utilizar el evento OnHint de la variable de Aplicación


global, en aplicaciones Delphi, para mostrar sugerencias de elementos de
menú (largos) en una barra de estado .
• Windows no expone los mensajes necesarios para admitir un evento
OnMouseEnter tradicional. Sin embargo, el mensaje WM_MENUSELECT
se envía cuando el usuario selecciona un elemento del menú.

• La implementación WM_MENUSELECT de TCustomForm (ancestro del


TForm) establece la sugerencia del elemento de menú en Application.Hint
que se puede utilizar en el evento Application.OnHint.

• Si desea agregar sugerencias emergentes de elementos de menú


(información sobre herramientas) a los menús de la aplicación Delphi, * solo
* necesita manejar el mensaje WM_MenuSelect correctamente.

• La clase TMenuItemHint: sugerencias emergentes para elementos de


menú.
• Dado que no puede confiar en el método Application.ActivateHint para
mostrar la ventana de sugerencia para los elementos del menú (ya que el
manejo del menú está completamente hecho por Windows), para obtener la
ventana de sugerencia que se muestra debe crear su propia versión de la
ventana de sugerencia - derivando un nuevo clase desde THintWindow .

• Aquí le mostramos cómo crear una clase TMenuItemHint : ¡una sugerencia


de viuda que realmente se muestra para los elementos del menú!

• Primero, necesita manejar el mensaje WM_MENUSELECT de Windows:

• > tipo TForm1 = clase (TForm) ... procedimiento privado WMMenuSelect


( var Msg:
TWMMenuSelect); mensaje WM_MENUSELECT; fin ... implementación ... procedimi
ento TForm1.WMMenuSelect ( var Msg: TWMMenuSelect); var menuItem:
TMenuItem; hSubMenu: HMENU; comenzar heredado ; // desde TCustomForm (para
que Application.Hint esté asignado) menuItem: = nil ; if (Msg.MenuFlag <> $
FFFF) o (Msg.IDItem <> 0) luego comienzan si Msg.MenuFlag y MF_POPUP =
MF_POPUP luego comienzan hSubMenu: = GetSubMenu (Msg.Menu,
Msg.IDItem); menuItem: = Self.Menu.FindItem (hSubMenu,
fkHandle); end else begin menuItem: = Self.Menu.FindItem (Msg.IDItem,
fkCommand); fin ; fin ; miHint.DoActivateHint (elemento del menú); fin ; (*
WMMenuSelect *)

• Información rápida: el mensaje WM_MENUSELECT se envía a la ventana


de propietario de un menú (Form1!) Cuando el usuario selecciona (¡no hace
clic!) Un elemento del menú. Usando el método FindItem de la clase
TMenu, puede obtener el elemento de menú actualmente seleccionado. Los
parámetros de la función FindItem se relacionan con las propiedades del
mensaje recibido. Una vez que sabemos en qué elemento del menú está el
mouse, llamamos al método DoActivateHint de la clase TMenuItemHint.
Nota: la variable miHint se define como "var miHint: TMenuItemHint" y se
crea en el controlador de eventos OnCreate del formulario.

• Ahora, lo que queda es la implementación de la clase TMenuItemHint.

• Aquí está la parte de la interfaz:

• > TMenuItemHint = clase (THintWindow) private activeMenuItem:


TMenuItem; showTimer: TTimer; hideTimer: TTimer; procedimiento HideTime
(Sender: TObject); procedimiento ShowTime (Sender:
TObject); public constructor Create (AOwner:
TComponent); anular ; procedimiento DoActivateHint (menuItem:
TMenuItem); destructor Destroy; anular ; fin ;

• Puede encontrar la implementación completa en el proyecto de muestra.

• Básicamente, la función DoActivateHint llama al método ActivateHint de


THintWindow utilizando la propiedad Pista de TMenuItem (si está
asignada).


El showTimer se utiliza para garantizar que la HintPause (de la Aplicación)
transcurra antes de que se muestre la pista. El hideTimer usa
Application.HintHidePause para ocultar la ventana de sugerencia después
de un intervalo especificado.

• ¿Cuándo usarías las Sugerencias de elementos de menú?


• Mientras que algunos podrían decir que no es un buen diseño para mostrar
sugerencias para los elementos del menú, hay situaciones en las que
mostrar las sugerencias de los elementos del menú es mucho mejor que
usar una barra de estado. Una lista de elementos de menú de uso más
reciente (MRU) es uno de estos casos. Un menú personalizado de la barra
de tareas es otro.

• Sugerencias de elementos de menú en aplicaciones Delphi


• Crea una nueva aplicación Delphi. En la forma principal, suelte a ("Menú1") TMenu
(paleta estándar), una barra de herramientas TStatusBar (paleta Win32) y un
componente TApplicationEvents (paleta adicional). Agregue varios elementos de
menú al menú. Permita que algunos elementos del menú tengan asignada una
propiedad de Pista, permita que algunos elementos del menú sean Sugerencia
"libre".

• Aquí está el código fuente completo (descarga) de la Unidad del formulario,


junto con la implementación de la clase TMenuItemHint :
• unidad Unidad1;

interfaz

usos
Windows, Mensajes, SysUtils, Variantes, Clases, Gráficos,
Controles, Formularios, Diálogos, Menús, AppEvnts,
StdCtrls, ExtCtrls, ComCtrls;

tipo
TMenuItemHint = clase (THintWindow)
privado
activeMenuItem: TMenuItem;
showTimer: TTimer;
hideTimer: TTimer;
procedimiento HideTime (Sender: TObject);
procedimiento ShowTime (Sender: TObject);
público
constructor Create (AOwner: TComponent); anular ;
procedimiento DoActivateHint (menuItem: TMenuItem);
destructor Destroy; anular ;
fin ;

TForm1 = clase (TForm)


...
procedimiento FormCreate (Sender: TObject);
procedimiento ApplicationEvents1Hint (Sender: TObject);
privado
miHint: TMenuItemHint;
procedimiento WMMenuSelect ( var Msg:
TWMMenuSelect); mensaje WM_MENUSELECT;
fin ;

var
Form1: TForm1;

implementación
{$ R * .dfm}

procedure TForm1.FormCreate (Sender: TObject);


empezar
miHint: = TMenuItemHint.Create (self);
fin ; (* FormCreate *)

procedure TForm1.ApplicationEvents1Hint (Sender: TObject);


empezar
StatusBar1.SimpleText: = 'App.OnHint:' + Application.Hint;
fin ; (* Application.OnHint *)

procedure TForm1.WMMenuSelect (var Msg: TWMMenuSelect);


var
menuItem: TMenuItem;
hSubMenu: HMENU;
empezar
heredado ; // desde TCustomForm (asegura que Application.Hint está
asignado)

menuItem: = nil ;
if (Msg.MenuFlag <> $ FFFF) o (Msg.IDItem <> 0) luego
empezar
si Msg.MenuFlag y MF_POPUP = MF_POPUP, entonces
empezar
hSubMenu: = GetSubMenu (Msg.Menu, Msg.IDItem);
menuItem: = Self.Menu.FindItem (hSubMenu, fkHandle);
fin
más
empezar
menuItem: = Self.Menu.FindItem (Msg.IDItem, fkCommand);
fin ;
fin ;

miHint.DoActivateHint (elemento del menú);


fin ; (* WMMenuSelect *)

{TMenuItemHint}
constructor TMenuItemHint.Create (AOwner: TComponent);
empezar
heredado ;

showTimer: = TTimer.Create (self);


showTimer.Interval: = Application.HintPause;

hideTimer: = TTimer.Create (self);


hideTimer.Interval: = Application.HintHidePause;
fin ; (*Crear*)

destructor TMenuItemHint.Destroy;
empezar
hideTimer.OnTimer: = nil ;
showTimer.OnTimer: = nil ;
self.ReleaseHandle;
heredado ;
fin ; (*Destruir*)

procedimiento TMenuItemHint.DoActivateHint (menuItem: TMenuItem);


empezar
// fuerza eliminar la ventana de sugerencia "vieja"
hideTime (uno mismo);

if (menuItem = nil ) o (menuItem.Hint = '') luego


empezar
activeMenuItem: = nil ;
Salida;
fin ;

activeMenuItem: = elemento del menú;

showTimer.OnTimer: = ShowTime;
hideTimer.OnTimer: = HideTime;
fin ; (* DoActivateHint *)

procedimiento TMenuItemHint.ShowTime (Sender: TObject);


var
r: TRect;
wdth: entero;
hght: entero;
empezar
if activeMenuItem <> nil, entonces
empezar
// posición y cambio de tamaño
wdth: = Canvas.TextWidth (activeMenuItem.Hint);
hght: = Canvas.TextHeight (activeMenuItem.Hint);

r.Left: = Mouse.CursorPos.X + 16;


r.Top: = Mouse.CursorPos.Y + 16;
r.Right: = r.Left + wdth + 6;
r.Bottom: = r.Top + hght + 4;

ActivateHint (r, activeMenuItem.Hint);


fin ;

showTimer.OnTimer: = nil ;
fin ; (*Tiempo de la funcion*)

procedimiento TMenuItemHint.HideTime (Sender: TObject);


empezar
// esconder (destruir) ventana de sugerencia
self.ReleaseHandle;
hideTimer.OnTimer: = nil ;
fin ; (* HideTime *)

fin

Cómo seleccionar MultiSelect en Delphi


DBGrid
• by Zarko Gajic

El DBGrid de Delphi es uno de los componentes más conocidos de DB en


aplicaciones relacionadas con bases de datos. Su objetivo principal es permitir que
los usuarios de su aplicación manipulen los registros de un conjunto de datos en
una cuadrícula tabular.

Una de las características menos conocidas del componente DBGrid es que se


puede configurar para permitir la selección de múltiples filas. Lo que esto significa
es que sus usuarios pueden tener la capacidad de seleccionar múltiples registros
(filas) del conjunto de datos conectado a la red.

Permitir selecciones múltiples

Para habilitar la selección múltiple, solo necesita establecer el


elemento dgMultiSelect en "Verdadero" en la propiedad Opciones .
Cuando dgMultiSelect es "Verdadero", los usuarios pueden seleccionar múltiples
filas en una grilla usando las siguientes técnicas:

▪ Ctrl + clic del mouse


▪ Shift + teclas de flecha
Las filas / registros seleccionados se representan como marcadores y se
almacenan en la propiedad SelectedRows de la cuadrícula.

Tenga en cuenta que SelectedRows solo es útil cuando la propiedad Options se


establece en "True" para dgMultiSelect y dgRowSelect . Por otro lado, al
usar dgRowSelect (cuando no se pueden seleccionar celdas individuales), el
usuario no podrá editar registros directamente a través de la grilla y, y dgEditing se
configurará automáticamente en "False".

La propiedad SelectedRows es un objeto de tipo TBookmarkList . Podemos usar la


propiedad SelectedRows para, por ejemplo:

▪ Obtenga la cantidad de filas seleccionadas


▪ Borrar la selección (deseleccionar)
▪ Eliminar todos los registros seleccionados

▪ Verifique si se seleccionó un registro en particular


Para establecer dgMultiSelect en "Verdadero", puede usar el Inspector de
Objetos en tiempo de diseño o usar un comando como este en tiempo de
ejecución:

DBGrid1.Options: = DBGrid1.Options + [dgMultiSelect];

dgMultiSelect Ejemplo

Una buena situación para usar dgMultiSelect podría ser cuando necesite una
opción para seleccionar registros aleatorios o si necesita la suma de los valores de
los campos seleccionados.

El siguiente ejemplo utiliza componentes ADO ( AdoQuery conectado


a ADOConnection y DBGrid conectado a AdoQuery sobre DataSource ) para
visualizar los registros de una tabla de base de datos en un componente DBGrid.

El código usa selección múltiple para obtener la suma de los valores en el campo
"Tamaño". Utilice este código de ejemplo si desea seleccionar todo el DBGrid :

procedimiento TForm1.btnDoSumClick (Sender: TObject); var i: entero; suma:


Individual; comience si DBGrid1.SelectedRows.Count> 0 luego begin sum: =
0; con DBGrid1.DataSource.DataSet do begin for i: =
0 to DBGrid1.SelectedRows.Count-1 comenzar GotoBookmark (Puntero
(DBGrid1.SelectedRows.Items [i])); sum: = suma + AdoQuery1.FieldByName
('Tamaño'). AsFloat; fin ; fin ; edSizeSum.Text: = FloatToStr (suma); extremo final ;

Manejo de errores y excepciones en


aplicaciones Delphi
• by Zarko Gajic
• ¡La línea de código más libre de errores es la que no tiene que escribir!

• Desafortunadamente, la construcción de aplicaciones incluye codificación.


Independientemente de cuán cuidadosamente escriba / depure su
programa, será imposible imaginar cada situación que pueda salir mal. El
usuario inexperto podría, por ejemplo, intentar abrir un archivo inexistente o
ingresar un valor incorrecto en un campo de datos.
Los usuarios cometen errores y debemos estar preparados para manejar /
prevenir estos errores donde sea y cuando sea posible.
• Errores, Excepciones?
• Una excepción generalmente es una condición de error u otro evento que
interrumpe el flujo normal de ejecución en una aplicación. Cuando se
produce un error al procesar una línea de código, Delphi crea (aumenta) un
descendiente de objeto de TObject llamado objeto de excepción.

• Bloques guardados
• Una aplicación responde a una excepción ejecutando un código de
terminación, manejando la excepción o ambas. La forma de habilitar la
captura de error / excepción dentro de un código dado, la excepción debe
ocurrir dentro de un bloque de instrucciones oculto. El código general se ve
así:

• > prueba {bloque de código guardado} excepto en do begin {exception block-


handleles SomeException} end; fin;

• Una instrucción try / except ejecuta las instrucciones en el bloque de


código protegido. Si las instrucciones se ejecutan sin que se genere
ninguna excepción, se ignora el bloque de excepción y el control pasa a la
instrucción que sigue a la palabra clave final.

• Ejemplo:

• > ... Cero: = 0; try dummy: = 10 / Zero; excepto en EZeroDivide do MessageDlg ('No
se puede dividir por cero!', mtError, [mbOK], 0); fin; ...

• Protección de recursos
• Cuando una sección de código adquiere un recurso, a menudo es
necesario garantizar que el recurso se libera nuevamente (o puede tener
una fuga de memoria ), independientemente de si el código se completa
normalmente o si se interrumpe con una excepción.

• En este caso, la sintaxis utiliza finalmente la palabra clave y se ve así:

• > {algún código para asignar recursos} intente {bloque de código guardado}
finalmente {bloque de terminación - código para liberar recursos} final;

• Ejemplo:

• > ... AboutBox: = TAboutBox.Create (nil); prueba AboutBox.ShowModal; finalmente


AboutBox.Release; fin; ...

• Application.OnException
• Si su aplicación no maneja el error que causó la excepción, Delphi usará su
manejador de excepción predeterminado: aparecerá un cuadro de mensaje.
Puede considerar escribir código en el evento OnException para el objeto
TApplication, para atrapar errores en el nivel de la aplicación.
• Break On Exceptions
• Al crear un programa con manejo de excepciones, es posible que no desee
que Delphi incumpla las Excepciones. Esta es una gran característica si
desea que Delphi muestre dónde se ha producido una excepción; sin
embargo, puede ser molesto cuando prueba su propio manejo de
excepciones.

• Pocas palabras finales


• La idea de este artículo es darle una rápida mirada a las excepciones. Para
una discusión más detallada sobre el manejo de excepciones, considere
el Manejo de excepciones en el manejo de excepciones de Delphi , usando
una herramienta como Delphi Crash / Exception Handling con Bug
Reporting y algunos de los siguientes artículos relacionados:

Вам также может понравиться