Archivo

Archivo para la categoría ‘Delphi’

Utilizar ADO con Threads

viernes, 14 de enero de 2011 1 comentario
Share Button

Los threads (o hilos de ejecución), en general, se ven como un tema peliaudo; Son unas «cosas» que están ahí, son buenas (eso dice todo el mundo), pero cuando más se tarde en tener que tacarlos, mejor…  ;-D

Recuerdo que cuando empecé en esto de la programación, los threads o la «programación con múltiples hilos de ejecución» sonaba algo así como «muy difícil». A medida que va pasando el tiempo, uno se da cuenta que que no es así, y cuando has hecho unos cuantos ejemplos te das cuenta de la potencia que aportan y de que realmente sólo hay que tener algunas «precauciones» a la hora de utilizarlos.

En este misma página podéis encontrar algunos ejemplos («ping usando threads», Ejemplo visual y Ejemplo visual ampliado) de programación de hilos de ejecución con Delphi. Ejemplos bastantes sencillos y bastante inútiles, porqué no decirlo, exceptuando la utilidad de aprender cómo funcionan y poder ver un código simple de utilización.

La idea de esta entrada es ir un poco más allá. A veces nos encontramos en una aplicación, con determinadas consultas que tardan mucho tiempo y que no es imprescindible esperar a su finalización para poder continuar con la ejecución normal del programa. Las más comunes serías típicas consultas de Listados, estadísticas o determinadas operaciones que podríamos hacer en 2º plano. Esas consultas serían las candidatas ideales para poder lanzarlas en un Thread independiente del hilo principal del programa.

Para los ejemplos voy a utilizar los componentes ADO y accederemos a la Base de Datos dbdemos.mdb que viene con Delphi.

Para trabajar con ADO utilizando threads, o para lanzar consultas dentro de threads, la única condición es que la conexión (TADOConnection) se cree dentro del mismo thread. Utilizaremos para ello una «cadena de conexión» como propiedad del Thread.

La estructura de la clase podría ser algo así:

TADOSQLThread = class(TThread)
  private
    FADOQ: TADOQuery;
    FSQL: string;
    FTotalTime:string;
  public
    constructor Create(CreateSuspended:Boolean; AConnString:String;
                       ASQL:string);
    destructor Destroy; override;
    procedure Execute(); override;
    property SQL:string read FSQL write FSQL;
    property ADOQ:TADOQuery read FADOQ write FADOQ;
    property TotalTime:string read FTotalTime;
end;

Para lanzar desde una aplicación una consulta utilizando nuestra clase TADOSQLThread , debería bastar con asignar la conexión, la cadena SQL, lanzar nuestro thread y esperar a que acabe. El código podría ser este:

  //crear el Thread; Pasamos los parámetros de conexión y SQL
  th := TADOSQLThread.Create(True, AConnection, ASQL);
  // Evento finalizacion; Al finalizar el control me llegará hasta este evento.
  th.OnTerminate := TerminateThread;
  // Ejecutarlo (ponerlo en marcha)
  th.Resume;

El código operativo del thread es sencillo, se encuentra en el método Execute y lo único que hace es ejecutar la consulta; En el constructor cremos la nueva Query (con una nueva conexión) y asignamos la SQL.

constructor TADOSQLThread.Create(CreateSuspended:Boolean;
           AConnString:String; ASQL:string);
begin
  // Creamos el thread inicialmente suspendido (para asignarle las props.)
  inherited Create(CreateSuspended);
  // No liberar automáticamente
  Self.FreeOnTerminate := False;
  //crea el query
  FADOQ := TAdoquery.Create(nil);
  FADOQ.ConnectionString := AConnString;
  FADOQ.SQL.Add(ASQL);
  Self.FSQL:= ASQL;
end;
 
procedure TADOSQLThread.Execute();
begin
  inherited;
  // Ejecutar la consulta
  Self.FADOQ.Open;
end;

Ahora haría falta probar si en la ejecución de una serie de sentencia SQL con y sin threads se aprecian diferencias visibles. Hay que tener en cuenta que el utilizar o no threads también implica otras cosas.

No todo en este escenario son ventajas, hay que tenerlo en cuenta y entender el funcionamiento para sopesar si en cada caso concreto es beneficioso utilizar threads. Hay 2 grandes inconvenientes que a priori se detectan fácilmente cuando se ejecuta y se prueba un ejemplo como el que vamos a realizar.

Gasto de conexiones: En una ejecución normal, las consultas que se lanzan utilizan todas la misma conexión (ADOConnection); Una premisa que hemos marcado para trabajar con threads, es que cada thread debe funcionar con su conexión propia. Esto implica que en un caso estamos utilizando una única conexión y en el otro X conexiones concurrentes. Esto puede ser un problema en segun qué sistemas.

Sobrecarga de tiempo: El segundo problema (derivado en cierta manera del primero) es la sobrecarga de tiempo que la creación y activación de las nuevas conexiones provoca. Crear, activar (sobre todo este) y liberar las conexiones de cada thread es un tiempo añadido que hay que tener en cuenta.

Estos 2 problemas no se puede solucionar (del todo), pero sí mitigar utilizando un «pool de conexiones«; No es un tema para desarrollar ahora (tal vez más adelante), pero la idea explicada de forma sencilla, es que podemos utilizar un número máximo de conexiones (no tantas como threads). De esta forma, se asigna una conexión libre a un thread cuando la necesita, mientras haya conexiones libres; Cuando ya no quedan libres, el thread debe esperar a que una finalice para que le sea asignada. De esta forma podemos fijar el número máximo de conexiones que se utilizan y además optimizar tiempo, ya que esas conexiones se pueden «reaprovechar» de forma que no exista la necesidad de crear/activar/destruir cada una de ellas.

¿Cuando usar threads y cuando no?

La regla sencilla sería: «Cuanto más grandes y pesadas sean las consultas, más a cuenta sale utilizar threads».

Si lanzamos 20 consultas que tardan muy poco tiempo, el retraso en crear/activar las conexiones de cada una de ellas puede hacer que el tiempo de preparación sea mayor que el de la propia consulta; En ese caso estaremos «gastando» mas tiempo en «preparar» que en «consultar. Por el contrario si esas 20 consultas tardan 30 segundos cada una, el tiempo de extra de conectar para cada una de ellas puede pasar desapercibido (cuando mayor sea el tiempo de consulta, más eficiente este sistema).

Resultado de las pruebas

En las pruebas he lanzado una serie de consultas de forma secuencial. Hay que notar que el tiempo total (para consultas grandes) es sensiblemente menos cuando utilizamos threads; Pero no sólo hay que tener en cuenta el tiempo total, sino el intervalo en que tenemos acceso al resultado de cada consulta.

De forma secuencial, si la primera consulta tarda 10, la segunda 5 y la tercera 7; El tiempo total es de 22, pero los tiempos de acceso a los resultados son 10, 15 y 22 segundos respectívamente; En cambio si esto se hiciera con threads, aun suponiendo que el tiempo total fuera el mismo, los tiempo de acceso a los resultados serían 10, 5 y 7 segundos.

Select * from CustomerSelect * from Employee
Select * from CountrySelect * from items
Select * from Parts

Select * from VendorsSELECT employee.* FROM employee ORDER BY Salary,
LastName DESC , FirstName DESC , HireDate DESC

SELECT employee.* FROM employee ORDER BY Salary DESC

SELECT customer.*, orders.*, items.*, parts.*, vendors.*,
vendors.State, items.Discount, orders.SaleDate, *
FROM vendors INNER JOIN (parts INNER JOIN ((customer INNER JOIN orders
ON customer.CustNo = orders.CustNo)
INNER JOIN items ON orders.OrderNo = items.OrderNo)
ON parts.PartNo = items.PartNo)
ON vendors.VendorNo = parts.VendorNo
ORDER BY vendors.State, items.Discount DESC , orders.SaleDate

La primera prueba consta de una serie de consultas que tardan muy poco tiempo, con la Base de Datos de Access DBDEMOS.MDB (que se adjunta con Delphi). En este caso se puede ver que los tiempos de las consultas individuales son sensíblemente más bajos sin threads que con threads, debido a que las consultas con threads incluyen el tiempo de conexión. Finalmente aunque los tiempos individuales son mayores (con threads) el tiempo total queda bastante igualado (se compensa la ejecución con threads con la pérdida en las conexiones).

DATOS SIN THREADS.

DATOS CON THREADS

¿Qué pasaría si lanzáramos algunas consultas que tarden más tiempo?

Para el ejemplo he utilizado datos propios conectando a SQL Server, ya que los de la Base de Datos DBDEMOS sólo nos sirven para realizar pequeñas pruebas. Os animo a que cambieis la conexión ADO que viene en el ejemplo y configuréis vuestra propia conexión y vuestras propias consultas para realizar las pruebas.

Para la conexión basta con pulsar el botón que aparece en la parte derecha de la conexión:

Y para las consultas,  basta con tener la precaución de colocar el caracter @ al inicio de cada una de las SQL (sólo cuando empieza la consulta, no en el salto de línea).

En este caso, vemos que los resultados sí cambian sensiblemente; Lo primero que nos llama la atención, es la diferencia de tiempo total de la serie de consultas (con y sin threads); He realizado unas cuantas ejecuciones, alternando primero unas y luegos las otras y los resultados de tiempos son estos; Los primeros son las consultas normales y los segundos con threads:

Sin threads:

·············································
Tiempo total(todo): 01:19:359
Tiempo total(todo): 01:18:516
Tiempo total(todo): 01:04:500
Tiempo total(todo): 01:08:969
Tiempo total(todo): 01:09:718
·············································

Con threads:

·············································
Tiempo total con threads(todo): 01:00:000
Tiempo total con threads(todo): 00:46:800
Tiempo total con threads(todo): 00:45:484
Tiempo total con threads(todo): 00:53:078
·············································

Posteriormente he lanzado, para variar, 4 ejecuciones concurrentes de ejemplo; 2 con threads y 2 sin threads y el resultado ha sido similar (en cuanto a la diferencia):

·············································
Tiempo total(todo): 01:48:984
Tiempo total(todo): 01:50:860
·············································
·············································
Tiempo total con threads(todo): 01:27:593
Tiempo total con threads(todo): 01:32:860
·············································

CONCLUSIÓN: Aunque el ejemplo es bastante sencillo, y la clase que implementa los threads tiene poca «chicha» yo creo que se ven las posibilidades de utilizar esta opción. También debe quedar claro que no es algo para usar «siempre»; Hemos visto que dependiendo del escenario donde se utiliza puede resultar inútil e incluso contraproducente, ya que gasta más recursos que la técnica sin threads. Como ventaja tenemos que la utilización de threads, en general, nos aporta paralelismo y mayor control en la ejecución del programa (ya que evitamos el «bloqueo» en el caso de una consulta muy costosa).

El código fuente del ejemplo, el binario podeís descargarlo desde aquí.

<DESCARGAR CODIGO FUENTE>

Un saludo.

 
Categories: Artículos, Delphi, OOP Tags: , ,

[APP] IBPIndex v.1.7b; Información sobre Tracks (GPS)

sábado, 1 de enero de 2011 33 comentarios
Share Button

ACTUALIZACIÓN:  Debido a cambios en la política de Google Maps hay una nueva actualización del programa IBPIndex.  

IBPIndex es una aplicación que permite obtener información y visualizar sobre un mapa, rutas en formato GPX (GPS eXchange Format), GTM (GPS Trackmaker), KML (Google Earth), PLT (OziExplorer), TCX (Garmin Training Center), GDB (Mapsource), TRK (CompeGPS), TRL (Alan Map500 TrackLog), MPS (Garmin Mapsource), UPT (Magellan File -eXplorist-) y XOL (Swiss Map 25/50/100).

Está pensado (o enfocado) a la carga de archivos que provienen desde un dispositivo GPS.

TrackInfo

INFORMACIÓN:

  • Funciona en todas las versiones de Windows.
  • NEW Versión 1.7 (beta)  del 15/12/2011
  • La aplicación se puede usar y distribuir de forma totalmente gratuíta.

 

CARACTERÍSTICAS:

  • Visualización de los puntos de ruta sobre un gráfico; Información de puntos. Zoom, impresión, exportación…
  • Permite abrir y convertir tracks en los siguientes formatos:

GPS Trackmaker (*.GTM)
Google Earth (*.KML)
OziExplorer (*.PLT)
Garmin Training Center (*.TCX)
Mapsource (*.GDB)
CompeGPS (*.TRK)
GPS Exchange Format (*.GPX)
Alan Map500 TrackLog (*.TRL)
Garmin Mapsource (*.MPS)
Magellan File -eXplorist- (*.UPT)
Swiss Map 25/50/100 (*.XOL)

  • Exportación con interface a GPSBabel a otros formatos
  • Configuración de múltiples idiomas y fácil creación de nuevos (aplicación).
  • Gráficos de altura y velocidad de la ruta.
  • Información puntual para los puntos de la ruta.
  • Animación de rutas/recorridos gráficamente.
  • Visualización de las rutas sobre Google Maps. Exportación e impresión de mapas.
  • Visualización de Perfil de altura de los datos el track. Exportación como imagen.
  • Interface Ribbon.
  • Información del IBPIndex de la ruta (www.ibpindex.com); Impresión y exportación a PDF.
  • Actualizaciones automáticas desde Internet.
  • Visualización en Google Maps en 3D utilizando pluging de Google Earth.

 

IMAGENES:

Click sobre las imagenes para agrandar.

Interface Ribbon de la aplicación (principal) .

Interface Ribbon

Otras ventanas de la aplicación (principal de Datos, Gráfico, Google Maps, Perfil, IBPIndex,…)

Ventana principal de DatosVentana de gráficoGoogle MapsPantalla IBPIndexConversión de rutas

INSTALACIÓN:

La aplicación se distribuye en un fichero instalable (setup_IBPIndex.exe). Basta con lanzar la instalación desde Windows y seguir las instrucciones del programa.

NOTA: En Vindows Vista y Windows 7 es necesario ejecutar la instalación con privilegios de administrador.

Si tiene problemas para instalar el programa, puede consultar aquí.

TRADUCCIONES

Si deseas añadir y cooperar en el desarrollo de la aplicación con nuevos idiomas, puedes hacerlo con unos sencillos pasos:

  1. Crea un nuevo fichero de idioma basándote en algunos de los ficheros de idioma presentes en la aplicación (es.lng, ca.lng, en.lng,…).
  2. Con un editor de texto (NOTEPAD, por ejemplo) traduce las constantes manteniendo la misma estructura que tienen; Especial atención a los símbolos especiales (&  *|* ).
  3. Envíamelo a la dirección <german_ral[ARROBA]hotmail.com> con tus datos.
  4. Una vez revisada y comprobada, la añadiré al programa con tus datos como traductor.

 

DESCARGA:

La aplicación se puede descargar desde esta misma web, o desde la web de IBPIndex (sección Aplicaciones).

Descarga desde aquí.  

Descarga desde IBP Index.

 

APORTA…

Esta aplicación es gratuíta y está realizada para utilizarla a nivel personal y por puro ocio. Me gusta la programación y me gusta la actividad de BTT, así que el resultado ha sido este.

Espero que a otras personas les pueda ser útil y aceptaré/agradeceré propuestas, ideas, correcciones, sugerencias,… para mejorarla y ampliarla.

 

HISTORIAL

Versión 1.7b (15/12/2001)

* Corregidos varios errores.
* mejoras en la visualización de mapas (Google Maps).

Versión 1.4b (12/05/2011)

ERRORES CORREGIDOS
* Corregidos errores de multiidioma. Se utiliza un sistema nuevo más abierto que permite añadir y traducir a nuevos idiomas mçás fácilmente
* Corregidos problemas al cargar ficheros con caracteres extraños en el nombre.
* Corregido error al mostrar elevación de ruta.
* Corregido error en el comando de conversión.
* Corregidos bugs menosres.

MEJORAS AÑADIDAS:
* Mejoras en el multiidioma (Cambio a un sistema más abierto).
* Admite rutas el multiples formatos a la hora de cargar.
* Carga e importa rutas más rápido (optimizado)
* Índice de carga de ruta
* Ajuste de columnas.
* Añadida traducción al Inglés y catalán.

 

Versión 1.2 (20/04/2011)

ERRORES CORREGIDOS:
* Error en el cuadro de arrastrar ruta; No admite arrastre.
* Corregido error en algunos equipos, que se quejan de que no exiaste MIDAS.DLL
* Corrección a la hora de actualizar la aplicación. En algunos casos no se descargaba
correctamente el fichero.
* Errores varios en la consulta del IBPIndex.
* Errores en los datos de rutas.

MEJORAS AÑADIDAS:
* Añadidos gráficos de velocidad y altura
* Sincronización de los puntos de cada gráfico
* Animación de la ruta visualmente.
* Información extendida de los puntos de la ruta.
* Título completo para la aplicación (incluyendo versión)
* Añadida información al gráfico referente a los puntos (Hora, distancia, acumulados,…).
* Ampliados los formatos de conversión de rutas.

Versión 1.1  (01/04/2011)

Versión inicial.

 

Un saludo.

 

 

Versión 1.5 del componente TSelectOnRuntime

viernes, 3 de diciembre de 2010 4 comentarios
Share Button

Hace unos días, a partir de unos comentarios y alguna petición sobre este componente por parte de usuarios, he corregido algun bug en el componente y he añadido algo de código. Actualizado la ayuda y recompilado las demos.

También he comprobado que funciona perfectamente en la nueva versión de Delphi, RAD Studio XE sin cambio alguno.

Corregidos unos problemas relacionados con los Anchors del componente y también cuando los componentes seleccionados tenían alineación alClient.

Para acceder a este componente puedes ir a la página de TSelectOnRuntime o acceder a la librería GLib completa desde aquí.

Categories: Componentes, Delphi Tags: ,

Presentación RAD Studio XE en Barcelona (24 Nov.)

jueves, 25 de noviembre de 2010 Sin comentarios
Share Button

El día 24 fue la presentación en Barcelona del nuevo RAD Studio XE. Siempre interesantes para conocer las novedades de las últimas versiones que las herramientas de Embarcadero. En este caso centrada en Delphi.

En la página de Facebook de Jordi Coll (Thundax Software) hay un par de fotos. No son muy buenas (supongo que Jordi las hizo desde su puesto con un teléfono), pero son muuuucho «mejores» que las que os puedo ofrecer yo.   ;-D

Dan una vista de la sala donde se ha celebrado los últimos años la presentación.

La verdad es que me hubiera gustado que Danysoft hubiera hecho alguna más y las hubieran publicado, o nos las hubiera distribuído para publicarlas en los blogs (petición que ya he hecho para la próxima vez).

La presentación fue a cargo de Luis Alfonso Rey; Interesante como siempre. Los ejemplos y demostraciones que suele mostrar no se ajustan a las típicas cosas que se ven en otras presentaciones. Suele intentar que estas sean originales y sobre temas no triviales; Lo que hace que en la mayoría de los casos tengan bastante interés (en algun otro caso resultan un poco «vagas», pero son lo que menos).  ;-)

En esta caso las demos y gran parte de la presentación ha girado en torno a DataSnap, donde parece que se encuentran algunas mejoras importantes que presenta la nueva versión. Además es un tema que por sus posibilidades «está de moda».



Por otro lado se encuentran las herramientas «auxiliares» que embarcadero ha decidido añadir a la versión XE, que merecen tema a parte y que también han tenido algo de tiempo en esta presentación.

AQTime del cual se ha realizado una pequeña demo para mostrar sus cualidades; Lanzar este profiler sobre una pequeña aplicación de muestra, para determinar los tiempos empleados por los diferentes procedimientos y comparar diferentes versiones de resultados, es insuficiente a todas luces, para mostrar las bondades y excelencias de esta herramienta. Y digo esto con conocimiento de causa, ya que lo he utilizado en su versión 3.5 y 4; Ya lo he comentado aquí antes, pero los calificativos que se me ocurren son «fantástica» e «imprescidible». Todo un acierto haber incluído esta herramienta con la nueva versión.
Actualmente se distribuye la versión 7, así que supongo que debe haber mejorado «algo» desde la versión que tuve el placer de utilizar.

FinalBuilder, que se distribuye también en su versión 7; No he tenido el placer de probarlo, pero por lo que se ha visto en la demo, es una herramienta que está condenada a utilizarse (u otra similar) en medianos/grandes proyectos. Ya no sólo por la comodidad que puede aportar al programador (generador de versiones), sino por la seguridad y robustez que puede aportar a este paso del proceso.

CodeSite. No tengo experiencia con él, pero lo que sí puedo decir es que he tenido que programar soluciones similares en alguno de mis proyectos (medianos/grandes); Así que si funciona mínimamente bien, creo que me evitará el trabajo de hacerlo por mi mismo en un futuro.

Ha habido en este caso también, tiempo para presentar algunas novedades en el IDE.  Me ha parecido «curiosa» e interesante la posibilidad de depurar los hilos de ejecución. También se ha hecho una breve reseña a las mejoras relacionadas con el tratamiento de expresiones regulares. Desconocidas para algunos de nosotros (aquí me incluyo yo, hasta ahora) e «indispensables» para otros, segun la naturaleza de los proyectos con los que estemos trabajando.

El tema de las licencia el algo aparte. De verdad, que al final vamos a tener que hacer un «Master» para poder enterarnos de cómo funcionan. Embarcadero cada vez (o al menos esa impresión me da a mi) complica más este tema. Se ha hablado en la presentación de ToolCloud en relación a esto, y que segun la web de Embarcadero es:

«Embarcadero ToolCloud centrally provisions and manages Embarcadero’s leading database management and application development tools».

Pues eso. Espero que os haya quedado ahora la cosa más clara (o al menos más que a mí).

Reseñas también a las mejoras que Embarcadero está realizando sobre el compilador para que sea más estable y rápido (descargar diapositiva PDF), en los esfuerzos para que en la web exista más material de ayuda y documentación (NOTA) y para corregir errores.
NOTA: En este caso parece que sigue olvidándose del Español como idoma a incluir es este bloque.  ;-(

Por lo demás, pues siempre es agradable cambiar el «ambiente» de la mesa de trabajo por uno diferente y ver a antiguos compañeros de trabajo para compartir experiencias con ellos.

Un saludo.

Categories: Delphi, Eventos, Offtopic Tags: ,

Componente TPanelMiniaturas v.1.1110

lunes, 22 de noviembre de 2010 18 comentarios
Share Button

TPanelMiniaturas es un componente pensado para gestionar una lista o colección de miniaturas, que enlazan con una lista de imágenes. Está pensado para gestionar la colección tanto en diseño como en ejecución.

Permite añadir imágenes de forma individual, en bloque (mediante una carpeta) y arrastrándolas desde el explorador.

Diferentes opciones para personalizar la lista de miniaturas.

Además permite gestionar de forma automática un «pase de diapositivas»; Se configura la velocidad de visualización y automáticamente el componente realiza un pase en «loop» por todas las imágenes almacenadas en la colección.

IMPORTANTE: Esta primera versión del componente no tiene en cuenta el consumo de memoria, algo que sí está previsto para las posteriores versiones, así que no es aconsejable utilizaro con un gran número de imágenes ni que tengan gran tamaño.

La autoría de este componente es compartida. De un ejemplo generado en mi web, Salvador Jover (Delphi básico) tuvo la idea de generar un componente; Creó la estructura básica utilizando colecciones y a partir de ahí, casi sin comerlo ni beberlo, fuimos añadiendo propiedades y características hasta generar esta primera versión.     ;-D

Tanto en mi web, como en la suya iremos publicando más cosas sobre el componente, así que si te interesa puedes estar atento a ambas. Igualmente aceptamos sugerencias, correcciones, modificaciones,… y cualquier otra que sirva para mejorarlo y enriquecerlo. El código está disponible para uso libre. Si realizáis cambios o mejoras os agradeceríamos que nos los comuniquéis para añadirlos al componenete.

Diseño de clases del componente (Click para agrandar).

Puedes descargar tanto los fuentes completos del componente como las demos compiladas, por si te interesa probarlo sin necesidad de instalarlo, en los siguientes enlaces:

<Sources TPanelMiniaturas>

<Demo EXE TPanelMiniaturas>

AÑADIDO(22/11): En el blog de Salvador podéis consultar una lista de Tarea/Bugs/Mejoras/…   tanto de esta primera versión, como las propuestas para las próximas. Algo así como el «estado actual» y el «libro de ruta» de este pequeño proyecto.

Un saludo.

Componente TPanelMiniaturas (En proceso…)

jueves, 4 de noviembre de 2010 4 comentarios
Share Button

A raiz de la última entrada de este blog respecto a crear componentes en un ScrollBox, y el ejemplo que desarrollé para mostrarlo creando un simple visualizador de imágenes y sus minuatura, Salvador (Delphi básico) y yo mismo, nos hemos propuesto crear un componente que permita gestionar estas miniaturas.

La idea inicial, era simplemente recordar y practicar determinados conceptos sobre componentes, pero poco a poco la cosa ha ido tomando forma y el resultado (por ahora en desarrollo todavía) se está tornando bastante interesante.

El componente TPanelMiniaturas está pensado como una colección  (TCollection) de minuaturas (TCollectionItems). Además se complementa con un componente adicional que se encarga de «pintar» las minuaturas en pantalla y que está ligado a cada ítem de la colección. Debe permitir gestionar esas miniaturas en diseño y en ejecución y facilitar al programador métodos para trabajar con ellas.

Podéis ver más imágenes y detalles del diseño del componente en esta entrada de la web de Salvador:  «Panel de miniaturas» y seguir las últimas ideas que se nos van ocurriendo aquí (debate en facebook). Estamos abiertos a cualquier idea y sugerencia, así que si alguien se anima, que «no se corte»…  ;-)

Un saludo.

Categories: Componentes, Delphi Tags: ,

Crear componentes en un TScrollBox (runtime)

martes, 26 de octubre de 2010 5 comentarios
Share Button

Se trata de un ejemplo sencillo que puede servir a quien esté comenzando con la creación de componentes en runtime y asignación de eventos. En este caso se trata de un visualizador de imágenes, que crea componentes TImage dentro de un TScrollBox, a modo de miniaturas, para luego visualizar esas imágenes en un control TImage a tamaño mayor.


Se utiliza también una TObjectList para almacenbar los objetos (componentes TImage y TPanel) que se van creando en ejecución para posteriormente poder acceder a ellos. Para crear los componentes se utiliza un código com este:

var
  im:TImage;
  i:Integer;
  pnl:TPanel;
begin
 
  // Para cada imagen
  for i := 0 to (imList.Count - 1) do begin
    // Crear el control imagen
    im := TImage.Create(nil);
    // Asignar propiedades
    im.Parent := ScrollBox1;
    im.Height := ScrollBox1.Height;
    im.Width := im.Height;
    im.Top := 0;
    im.Left := ((im.Width + 15{panel} + 4) * i);
    im.Transparent := true;
    im.Align := alLeft;
    im.Stretch := True;
    im.Proportional := True;
 
    // Cargar
    im.Picture.LoadFromFile(imList[i]);
    // vebto OnClick
    im.OnClick := ClickImage;
    // Añadirla a la lista de objetos
    oList.Add(im);
 
    // Separados
    pnl := TPanel.Create(nil);
    pnl.Parent := ScrollBox1;
    pnl.Left := im.Left + 5;
    pnl.Width := 15;
    pnl.Height := im.Height;
    pnl.Align := alLeft;
    pnl.Color := clBlack;
    // Aadirlo a la lista de objetos
    oList.Add(pnl);
 
  end;

Se puede descargar el código completo del ejemplo desde aquí .
Actualizo el contenido en DropBox.
Este ejemplo ha surgido a partir de este hilo en el ClubDelphi.

Otros ejempos útiles sobre el mismo tema, relacionados con este pueden ser «Crear, mover y redimensionar controles en Runtime (IDE)» o «Crear/destruir comp. en Runtime y moverlas con el ratón«.

Un saludo.

Categories: Delphi, Ejemplos, Fácil Tags: ,

Unir varias imágenes (TImage) en una sóla

jueves, 7 de octubre de 2010 Sin comentarios
Share Button

Hay un ejemplo antiguo en la página en la sección de ejemplos, titulado «Trocear un bitmap en n imágenes a modo de puzle». Hoy ha salido en los foros una pregunta sobre la operación contraria, ¿Cómo unir varios bitmaps (TImage) en una única imagen?

Puede ser algo trivial para los que llevamos un tiempo en esto, pero no tanto para los que empiezan; Reconozco que yo al principio también me liaba con los Canvas, los Rect, los ClientRect y no sabía cual copiar en cada cual.  ;-)

El código para unir cuatro imágenes en una sóla formando un cuadro, es muy sencillo y sería algo así:

var
  ARect:TRect;
  path:string;
begin
 
  // Añadir los 4 canvas a la nueva imagen
  ARect.Left := 0;  ARect.Top := 0; ARect.Right := 48; ARect.Bottom := 48;
  imgDestino.Canvas.CopyRect(ARect, img1.Canvas, img1.ClientRect);
  ARect.Left := 48;  ARect.Top := 0; ARect.Right := 92; ARect.Bottom := 48;
  imgDestino.Canvas.CopyRect(ARect, img2.Canvas, img2.ClientRect);
  ARect.Left := 0;  ARect.Top := 48; ARect.Right := 48; ARect.Bottom := 92;
  imgDestino.Canvas.CopyRect(ARect, img3.Canvas, img3.ClientRect);
  ARect.Left := 48;  ARect.Top := 48; ARect.Right := 92; ARect.Bottom := 92;
  imgDestino.Canvas.CopyRect(ARect, img4.Canvas, img4.ClientRect);
 
  // Path para grabarla a disco
  path := ChangeFileExt(Application.ExeName, '.bmp');
  imgDestino.Picture.SaveToFile(path);
  MessageDlg('Se ha guardado la imagen con el nombre: ' +
             path, mtInformation, [mbOK], 0);

Si en lugar de unirlas formando un cuadro, se quieren unir de otra forma (las 4 en línea, por ejemplo), basta con cambiar las coordenadas de destino.

Si hubiera que cambiar el tamaño final, por ejemplo para reducirlo hasta el de las imágenes originales, se podrían aplicar técnicas de antialiasing al redimensionar.

Descargar ejemplo.

Un saludo.

Categories: Delphi, Ejemplos Tags: ,

Póster de pared…

martes, 5 de octubre de 2010 1 comentario
Share Button

Si no os acaba de gustar o no es vuestro estilo, un póster como el de Raquel Welch, que cuelga Andrew Dufresne (Tim Robbins) en la película «Cadena perpetua», o simplemente sois un poco más «frikis» y/o  fans de Delphi, os adjunto este que hoy he visto en «TheRoadToDelphi» y que me ha traído gratos recuerdos.  ;-)

VCL Object Hierarchy

Un saludo.

Categories: Delphi, Humor, OOP Tags:

ENCUESTA: Sistema de control de versiones

lunes, 7 de junio de 2010 4 comentarios
Share Button

Después de un breve tiempo de innacividad, espero en breve volver a publicar de forma más asídua.

Vuelvo a publicar con una escuesta sobre los sistema de Control de Versiones.

Una de las cosas que creo básicas para un programador, cuando uno ya lleva un tiempo en esto y el volumen de código generado empieza a ser grande, es un  buen control de versiones, que además se puede utilizar como backup y repositorio de fuentes. Y ya no sólo cuando se trabaja en grupo, sino a nivel personal.

Para mi, es una de quellas cosas, que una vez que las pruebas, a no puedes «vivir» sin ellas.   ;-)

Os animo a que votéis y déis vuestra opinión.

Un saludo.