Continuando con las entradas anteriores, en esta última vamos a crear una extensión para visualizar los tipos de imágenes más habituales y usados en Windows. Además vamos a «redistribuir» un poco nuestro esqueleto inicial para reorganizar las clases (tal y como comentamos en entradas anteriores); Y finalmente vamos a crear un instalador para poder ofrecer esta extensión de una forma más profesional.
Os adjunto los links de todas las entradas de esta serie, como he hecho en las anteriores:
Con todo los visto hasta ahora en las entradas anteriores, vamos a crear una DLL para imágenes de diferentes formatos, modificando un poco el esqueleto del proyecto que teníamos hasta ahora.
Vamos a tratar las extensiones más comunes con las que trabajamos: bmp, jpg, jpeg, png, gif, ico, wmf, emf, tif, tiff
Además vamos a generar un instalador con Inno Setup que instale (y desinstale cuando sea necesario) nuestra DLL de previsualización. Inno Setup, para los que no lo conozcáis, es un generador de instalaciones para Windows muy potente y totalmente gratuito. En otras ocasiones ya he hablado de él, y a día de hoy es un estándar en generar programas de instalación.
Además de ser sencillo de utilizar, hay multitud de scripts predefinidos y de ejemplo por la web, que podéis utilizar, modificar y adaptar a vuestras necesidades. Para lo que necesitamos nosotros veréis que es sumamente sencillo y fácil.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Continuando el tema de «Crear una Previsualización de ficheros en Windows», vamos a seguir completando esta serie, haciendo referencia al tema del registro que nos quedó pendiente en la anterior entrada.
Os adjunto los links de todas las entradas de esta serie, que iré completando a medida que avance:
Hablo de «registros» en el título de esta entrada, porque vamos a abordar por un lado, los cambios en el «registro de Windows» que debemos realizar para que nuestra DLL quede «inscrita» en el sistema (con esto le decimos al sistema, que cuando quiera visualizar un determinado fichero de extensión AAA, debe cargar nuestra DLL para mostrar ese contenido). Y en segundo lugar, veremos cómo registrar nuestra DLL en Windows a través de regsrv32.
.
CLAVES DE REGISTRO
Cuando registramos nuestra DLL (regsvr32) necesitamos modificar algunos valores en el registro de Windows para indicar al sistema que tiene una DLL disponible para utilizar cuando se le solicite una vista previa de un archivo con extensión AAA.
Para ello tenemos disponible esta documentación que explica los diferentes cambios a crear/borrar cuando realizamos el register/unregister.
Lo primero que debemos tener en cuenta, es que si nuestro controlador de Vista previa (de 32 bits) se está registrando en un sistema de 64 bits, tal y como se describe aquí, debe usar un IdApp diferente;
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
En esta entrada me voy a centrar en el nuevo asistente «JSON Data Binding Wizard».
Anteriormente en otras entradas ya he realizado ejemplos para trabajar con ficheros JSON. A continuación os adjunto algunos links de entradas donde por diferentes necesidades he trabajado con archivos de este tipo:
Es junto al XML el formato más utilizado para intercambio de datos en la web y mayoritariamennte usado cuando descargamos información desde servidores REST mediante API, como se hace en las entradas anteriores.
Lo habitual en versiones antiguas de Delphi, es utilizar una librería externa ya que Delphi no la trae integrada (lkJSON, SuperObject,…) y en las versiones nuevas de Delphi ya se puede utilizar la que trae el propio Delphi (System.Json, REST.Json).
Lo que he necesitado hacer en esos ejemplos, es leer la estructura de datos y navegar por esa estructura jerárquica del JSON (similar al XML) e ir saltando por diferentes nodos hasta encontrar la información que necesitamos. Si el archivo es muy grande y la estructura compleja con muchos niveles, esta navegación (y su implementación puede ser más o menos compleja). Para escribir debemos completar los diferentes nodos de la estructura para finalmente generar el JSON.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Esta es la segunda entrada de la serie dedicada a pruebas unitarias. Si en la primera vimos una introducción a la programación guiada por pruebas, en esta segunda vamos a empezar a revisar los frameworks disponibles que nos ayudan a realizar los test unitarios.
Para realizar Test unitarios con Delphi disponemos de dos frameworks; Según la versión de Delphi podemos utilizarlos indistintamente, aunque a partir de la versión XE8 de Delphi, se recomienda utilizar DUnitX.
CREACIÓN DE PRUEBAS UNITARIAS (FRAMEWORKS)
Para realizar test unitarios con Delphi podemos utilizar los frameworks (ambos Open Source) DUnit y DUnitX.
A partir de la versión Delphi XE8 Embarcadero recomienda utilizar DUnitX, ya que DUnit ha quedado desactualizado. Si se ha trabajado con DUnit es relativamente fácil migrar los test ya existentes a DUnitX.
Lo que vamos a hacer es realizar los test con ambos paquetes y de esta forma también podremos ver las diferencias entre ambos y las ventajas prácticas que nos pueden aportar.
FRAMEWORK DUNIT
Para crear nuestro proyecto de pruebas unitarias que testee la clase TAritmeticaBasica de nuestra unit UClass.TAritmeticaBasica, podemos utilizar el asistente que ya trae el paquete. Si en nuestra versión de delphi no está instalado este paquete (DUnit), hay que descargarlo (de la dirección que hay más arriba) e instalarlo.
Lo primero es crear un proyecto que utilice nuestra Unit. Sería nuestra aplicación que va a utilizar esta unit. Para ello crearemos un nuevo proyecto llamado PAritmeticaBasica y le añadiremos la unit anterior.
A continuación vamos a generar, utilizando el asistente, el proyecto para las pruebas unitarias (y lo añadiremos al mismo grupo de proyectos). De esta forma tendremos nuestro proyecto y junto a el el proyecto de pruebas.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Bueno, si no te has enterado, ya llegas tarde. ;-D (aunque tienes otra oportunidad).
La semana pasada del 5 al 9 de Septiembre se han realizado las 5 sesiones online gratuitas de 2 horas cada una, sobre la última versión de Delphi (15:00 y 20:00 hora española).
Desde la propia página del Boot Camp donde estaba toda la información, tienes ahora acceso al replay de todas las sesiones realizadas.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Para complementar la entrada anterior (Hablando del tiempo… (OpenWeatherMap) 1/2) y «acabarla» me queda publicar el desarrollo móvil correspondiente a la aplicación que vimos anteriormente.
Como ya os comenté en la entrada anterior, el código a utilizar es prácticamente el mismo que hemos utilizado en las aplicaciones para windows (VCL). La mayor diferencia que me he encontrado en el tratamiento de la respuesta JSON que obtenemos del servidor.
Para versiones antiguas de Delphi, podéis utilizar si lo necesitáis la misma librería que ya he recomendado aquí otras veces. Se trata de lkJSON que podéis encontrar en Sourceforge.
En las nuevas versiones de Delphi ya está disponible la unit System.JSON, con lo necesario para no utilizar librerías externas.
function TForm1.ParseTiempoCiudadesHist(AObjResp: TlkJSONobject;var ATiempoProxHoras: TTiempoProxHoras):Boolean;var
i, j, num, index:integer;
oHorasList, OWList:TlkJSONlist;
oHora, oCoord, oMain, oWind, oWeather:TlkJSONobject;
Str:String;begin// ini
Result :=False;// Si no está asignado salimos..ifnotAssigned(AobjResp)thenbegin
Exit;end;// Si hay error no parseamosif IsErrorResponse(AObjResp, errCode, ErrMsg)thenbegin
Exit;end;// proteccion para el parseotry// cod. devuelto (datos principales
ATiempoProxHoras.Cod:= errCode;
num := AObjResp.IndexOfName('count');if(num <>-1)thenbegin
num := GetAsInteger(AObjResp.Field['count'].Value);end;// si no hay ciudadesif(num =0)thenbegin
MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', mtWarning,[mbOK],0);
Exit;end;// Lista de horas (Lista)
TlkJSONBase(oHorasList):= AObjResp.Field['list'];// array de elementosSetLength(ATiempoProxHoras.TiempoHora, oHorasList.Count);// Quedarse con el primier elemento de la lista...for i :=0to(oHorasList.Count-1)dobegin// datos de la primera ciudad
TlkJSONBase(oHora):= oHorasList.Child[i];// datos básicos
ATiempoProxHoras.TiempoHora[i].dt_text:= GetAsString(oHora.Field['dt_txt'].Value);// convertir fecha-Hora
Str := ATiempoProxHoras.TiempoHora[i].dt_text;
ATiempoProxHoras.TiempoHora[i].dt:= EncodeDateTime(StrToIntdef(Copy(Str,1,4),0),StrToIntdef(Copy(Str,6,2),0),StrToIntdef(Copy(Str,9,2),0),StrToIntdef(Copy(Str,12,2),0),StrToIntdef(Copy(Str,15,2),0),StrToIntdef(Copy(Str,18,2),0),0);// Load Main
TlkJSONBase(oMain):= oHora.Field['main'];
ATiempoProxHoras.TiempoHora[i].Main.temp:= GetAsFloat(oMain.Field['temp'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmin:= GetAsFloat(oMain.Field['temp_min'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmax:= GetAsFloat(oMain.Field['temp_max'].Value);
ATiempoProxHoras.TiempoHora[i].Main.pressure:= GetAsFloat(oMain.Field['pressure'].Value);
ATiempoProxHoras.TiempoHora[i].Main.humidity:= GetAsInteger(oMain.Field['humidity'].Value);// Load weather
TlkJSONBase(OWList):= oHora.Field['weather'];
TlkJSONBase(oWeather):= oWList.Child[0];
ATiempoProxHoras.TiempoHora[i].Weather.id:= GetAsInteger(oWeather.Field['id'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.main:= GetAsString(oWeather.Field['main'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.desc:= GetAsString(oWeather.Field['description'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.icon:= GetAsString(oWeather.Field['icon'].Value);end;
Result :=True;except// si hay error, FALSe
Result :=False;end;end;
function TForm1.ParseTiempoCiudadesHist(AObjResp: TlkJSONobject; var ATiempoProxHoras: TTiempoProxHoras): Boolean;
var
i, j, num, index:integer;
oHorasList, OWList:TlkJSONlist;
oHora, oCoord, oMain, oWind, oWeather:TlkJSONobject;
Str:String;
begin
// ini
Result := False;
// Si no está asignado salimos..
if not Assigned(AobjResp) then begin
Exit;
end;
// Si hay error no parseamos
if IsErrorResponse(AObjResp, errCode, ErrMsg) then begin
Exit;
end;
// proteccion para el parseo
try
// cod. devuelto (datos principales
ATiempoProxHoras.Cod := errCode;
num := AObjResp.IndexOfName('count');
if (num <> -1) then begin
num := GetAsInteger(AObjResp.Field['count'].Value);
end;
// si no hay ciudades
if (num = 0) then begin
MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', mtWarning, [mbOK], 0);
Exit;
end;
// Lista de horas (Lista)
TlkJSONBase(oHorasList) := AObjResp.Field['list'];
// array de elementos
SetLength(ATiempoProxHoras.TiempoHora, oHorasList.Count);
// Quedarse con el primier elemento de la lista...
for i := 0 to (oHorasList.Count - 1) do begin
// datos de la primera ciudad
TlkJSONBase(oHora) := oHorasList.Child[i];
// datos básicos
ATiempoProxHoras.TiempoHora[i].dt_text := GetAsString(oHora.Field['dt_txt'].Value);
// convertir fecha-Hora
Str := ATiempoProxHoras.TiempoHora[i].dt_text;
ATiempoProxHoras.TiempoHora[i].dt := EncodeDateTime(
StrToIntdef(Copy(Str, 1, 4), 0),
StrToIntdef(Copy(Str, 6, 2), 0),
StrToIntdef(Copy(Str, 9, 2), 0),
StrToIntdef(Copy(Str, 12, 2), 0),
StrToIntdef(Copy(Str, 15, 2), 0),
StrToIntdef(Copy(Str, 18, 2), 0), 0);
// Load Main
TlkJSONBase(oMain) := oHora.Field['main'];
ATiempoProxHoras.TiempoHora[i].Main.temp := GetAsFloat(oMain.Field['temp'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmin := GetAsFloat(oMain.Field['temp_min'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmax := GetAsFloat(oMain.Field['temp_max'].Value);
ATiempoProxHoras.TiempoHora[i].Main.pressure := GetAsFloat(oMain.Field['pressure'].Value);
ATiempoProxHoras.TiempoHora[i].Main.humidity := GetAsInteger(oMain.Field['humidity'].Value);
// Load weather
TlkJSONBase(OWList) := oHora.Field['weather'];
TlkJSONBase(oWeather) := oWList.Child[0];
ATiempoProxHoras.TiempoHora[i].Weather.id := GetAsInteger(oWeather.Field['id'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.main := GetAsString(oWeather.Field['main'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.desc := GetAsString(oWeather.Field['description'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.icon := GetAsString(oWeather.Field['icon'].Value);
end;
Result := True;
except
// si hay error, FALSe
Result := False;
end;
end;
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
He actualizado el contenido de la web en DropBox para que estén en todo momento accesibles los ejemplos, artículos, documentación,… Más detalles de todo ello en esta entrada.
He incluido los últimos ficheros añadidos a las entradas, la última versión de las librerías GLibWMI y los últimos ficheros de otras secciones como la de las rxLib en este blog.
Si os vais a dar de alta os agradecería que usarais esta invitación, de esta forma a ambos nos ofrecen un poco más de espacio, que nunca va mal… ;-)
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
IBPIndexCalc es una aplicación que permite obtener multitud de datos (en general «el grado de dificultad») de un Track/Ruta realizado en bicicleta (sea de carretera o de montaña). Aunque los datos podrían ser aplicados a cualquier track realizado en otra actividad.
Para ello el programa utiliza la web de IBPIndex (http://www.IBPIndex.com); Imprescindible para todos aquellos que salís en bici y utilizáis/generáis track con GPS.
Este índicxe IBP (Interactive Bicycling Parameters) se obtiene analizando los datos de latitud, longitud y altura en multitud de puntos del recorrido. A partir de estos puntos se calculan las distancias recorridas en los diferentes tramos de subidas y bajadas (1%, 5%, 10% etc..) se computan los % que representan sobre el total, los metros totales ascendidos, descendidos, los ratios medios de subida y de bajada, los Km. totales, y la distribución de los tramos de subida. Si queréis saber más y ampliar información sobre el tema visitad la web de IBPIndex (proceso de cálculo, corrección de errores, formato de puntuación,…).
IBPIndexCalc utiliza los componentes Indy para el acceso a la Web. Además implementa una clase derivada de TThread que permite que el pograma principal no se bloquee mientras espera la respuesta desde la web. Estructura de la Clase TWebThread:
{ : Clase para realizar consultas utilizando thread a la Web. }
TWebThread =class(TThread)private
IdHTTP: TidHTTP;
Stream: TIdMultipartFormDataStream;
FTrackFileName:string;
FwebBrowser: TWebBrowser;
FResponse:string;private
FURLNavigate:string;
FURLPDF:string;function _RepairLinks(StrPage:string;var URLpage:string;var UrlPDF:string):string;protectedpublic// ejecutar el procedimniento.procedure Execute;override;// componente de navegación.property webBrowser: TWebBrowser read FwebBrowser write FwebBrowser;// Fichero de Track/ruta.property TrackFileName:stringread FTrackFileName write FTrackFileName;// : Propiedad para recoger la respuesta desde la Web.property Response:stringread FResponse write FResponse;// URL de navegación.property URLNavigate:stringread FURLNavigate write FURLNavigate;// URL del PDF de respuesta.property UrlPDF:stringread FURLPDF;// : Constructor redefinido.constructor Create(AFileName:string; wb: TWebBrowser);end;
{ : Clase para realizar consultas utilizando thread a la Web. }
TWebThread = class(TThread)
private
IdHTTP: TidHTTP;
Stream: TIdMultipartFormDataStream;
FTrackFileName: string;
FwebBrowser: TWebBrowser;
FResponse: string;
private
FURLNavigate: string;
FURLPDF: string;
function _RepairLinks(StrPage: string; var URLpage: string;
var UrlPDF: string): string;
protected
public
// ejecutar el procedimniento.
procedure Execute; override;
// componente de navegación.
property webBrowser: TWebBrowser read FwebBrowser write FwebBrowser;
// Fichero de Track/ruta.
property TrackFileName: string read FTrackFileName write FTrackFileName;
// : Propiedad para recoger la respuesta desde la Web.
property Response: string read FResponse write FResponse;
// URL de navegación.
property URLNavigate: string read FURLNavigate write FURLNavigate;
// URL del PDF de respuesta.
property UrlPDF: string read FURLPDF;
// : Constructor redefinido.
constructor Create(AFileName: string; wb: TWebBrowser);
end;
Una vez que el programa obtiene respuesta de la Web, la analiza para detectar posibles errores y para extraer los links útiles al usuario. En este caso el PDF generado y la página de resultados.
La aplicación y la clase UTWebThread puede se útil, modificando determinados, para realizar un trabajo similar en otras páginas webs.
Es totalmente gratuíta y el código fuente está disponible.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…