sábado, 19 de septiembre de 2009

TFiltroDinamico: Una forma fácil y sencilla de generar filtros

Cuando desarrollamos aplicaciones es común que se realicen búsquedas por criterios definidos previamente --por lo regular uno, dos o tres campos--, pero...., que pasa si nos piden buscar por una combinación de todos los campos contenidos en nuestra tabla.

Ya me imagino la secuencia de pasos:

Para cada campo de la tabla:
  1. Pulsar Shift + Clic en el componente TLabel
  2. Cambiar los nombre del TLabel con el nombre del campo
  3. Pulsar Shift + Clic en el componente TComboBox para indicar los criterios (menor que, mayor que, etc..)
  4. Poner los cuadros de entrada para cada campo
y así sucesivamente.

Para facilitar ésta tarea, decidí crear la clase TFiltroDinamico, que nos apoya generando los nombres de los campos, combo boxes, cuadros de entrada y algo muy importante, si el campo es de tipo fecha genera un TDateTimePicker.

Un ejemplo de su uso es el siguiente:


// para crear una instancia
filtroDinamico := TFiltroDinamico.Create;
// dataset del cual toma los campos
filtroDinamico.dataSetLocal := Query1;
// scrollbox donde generan los filtros
filtroDinamico.scrlFiltro := scrlCampos;

// libera los filtros que se han creado
filtroDinamico.liberaComponentes;
// genera en el scrollbox los filtros
filtroDinamico.inicializaFiltro;

// obtiene la condición con el valor de cada campo.
filtroDinamico.obtenFiltro;
Este es un ejemplo de una aplicación que utiliza la clase TFiltroDinamico, el recuadro en rojo contiene los campos generados a partir de la información generada por la consulta, el recuadro en verde indica el valor que se asignó a cada campo.

Te invito a que descargues y pruebes TFiltroDinamico. Puedes probar la aplicación de ejemplo y compartirme que te parece.

jueves, 27 de agosto de 2009

Datos tipo Record en Delphi con soporte de métodos

Estaba desarrollando una aplicación que utilizaba coordenadas geográficas y tenía que hacer la conversión de Grados-Minutos-Segundos a su formato en Decimal, así que codifiqué de la siguiente forma:

type
TCoordenadaGeografica = Record
grados : Double;
minutos : Double;
segundos : Double;
End;

TConversion = class
class function gradosADecimales(grados: Double; minutos: Double; Segundos: Double):double; overload;
class function gradosADecimales(coordenadaGeografica: TCoordenadaGeografica):double;overload;
class function decimalesAGrados(valorDecimal :Double):TCoordenadaGeografica;
end;

implementation

{ TConversion }

class function TConversion.decimalesAGrados(
valorDecimal: Double): TCoordenadaGeografica;
var
resultado : TCoordenadaGeografica;
begin
resultado.grados := Int(valorDecimal);
resultado.minutos := Int((valorDecimal - resultado.grados)) * CONV_MINUTOS;
resultado.segundos := (resultado.minutos - Int(resultado.minutos)) * CONV_MINUTOS;
result := Resultado;
end;

class function TConversion.gradosADecimales(grados, minutos,
Segundos: Double): double;
var
resultado : Double;
begin
resultado := grados + (minutos / CONV_MINUTOS ) + (segundos / CONV_SEGUNDOS);
result := resultado;
end;

class function TConversion.gradosADecimales(
coordenadaGeografica: TCoordenadaGeografica): double;
var
resultado : Double;
begin
resultado := coordenadaGeografica.grados +
(coordenadaGeografica.minutos / CONV_MINUTOS ) +
(coordenadaGeografica.segundos / CONV_SEGUNDOS);
result := resultado;
end;


Todo funcionaba correctamente..., pero noté que estaba utilizando muchas líneas de código para hacer las conversiones:


procedure TfrmCaptura.asignaCoordenada(Sender: TObject);
var
latitud : TCoordenadaGeografica;
longitud : TCoordenadaGeografica;
begin
inherited;
latitud.grados := TConversion.toFloat(peaLatG.Text);
latitud.minutos := TConversion.toFloat(peaLatM.Text);
latitud.segundos := TConversion.toFloat(peaLatS.Text);

longitud.grados := TConversion.toFloat(peaLonG.Text);
longitud.minutos := TConversion.toFloat(peaLonM.Text);
longitud.segundos := TConversion.toFloat(peaLonS.Text);

// aquí se guarda en la base
end;
Tomando en cuenta que tenía que hacer ésto en varios lugares encontré la solución haciendo uso de las nuevas características de los Records en Delphi:


type
TCoordenadaGeografica = Record
grados : Double;
minutos : Double;
segundos : Double;
constructor Create(AGrados: Double; AMinutos:Double; ASegundos:Double); overload;
constructor Create(AGrados: String; AMinutos: String; ASegundos:String); overload;
End;

/// más líneas por acá

{ TCoordenadaGeografica }

constructor TCoordenadaGeografica.Create(AGrados, AMinutos, ASegundos: Double);
begin
Self.grados := AGrados;
Self.minutos := AMinutos;
Self.segundos := ASegundos;
end;

constructor TCoordenadaGeografica.Create(AGrados, AMinutos, ASegundos: String);
begin
Self.grados := TConversion.toFloat(AGrados);
Self.minutos := TConversion.toFloat(AMinutos);
Self.segundos := TConversion.toFloat(ASegundos);
end;


Por lo que me ahorré muchas lineas de código al hacer uso de los constructores en los Records:


procedure TfrmCaptura.asignaCoordenada(Sender: TObject);
var
latitud : TCoordenadaGeografica;
longitud : TCoordenadaGeografica;
begin
inherited;
latitud := TCoordenadaGeografica.Create(peaLatG.Text,peaLatM.Text,peaLatS.Text);
longitud := TCoordenadaGeografica.Create(peaLonG.Text,peaLonM.Text,peaLonS.Text);
// aquí se guarda en la base
end;

Otra opción hubiera sido el crear una clase de que se encargara de la conversión (que finalmente así quedó implementado) pero para mí fué una oportunidad de probar esta interesante característica de los Records en Delphi.

martes, 11 de agosto de 2009

guardaFotos: Facilitando la forma de guardar imágenes

En ocasiones por las prisas de sacar las fotos de nuestro teléfono celular o de la cámara digital no tenemos tiempo de organizarlas, o menos aún de seleccionar cuáles son las que realmente nos interesan.

Al principio son pocas carpetas y pocas fotos, pero con el tiempo no sabemos ni donde las dejamos, y no falta que llega la prima de la novia y nos dice:

"...hola!! cómo estás!!!, ¿Me podrías pasar las fotos que me tomaste con tu celular?, porfa!!"

comenzamos la conocida secuencia de pasos:

  • Abrir dos ventanas del explorador de Windows
  • Clic derecho en la barra de tareas
  • Seleccionar mosaico vertical
  • Seleccionar la foto
  • Dar vista previa
  • ¿Es la que nos interesa?, Si -> hacer el clásico Copiar y Pegar; No -> La que sigue

y así sucesivamente.

En un inicio todo funciona de maravilla, pero después de varios archivos Pegados aparece el famoso mensaje "El archivo ..... ya existe, desea sobreescribirlo" y algo que parecía ser fácil se nos empieza a complicar.

Después de haber pasado por esta experiencia, decidí desarrollar un programa (si en Delphi) que básicamente nos permite seleccionar la carpeta origen donde tenemos las fotos (con su respectiva vista previa), agregarlas en una lista que podemos guardar (por aquello de: "...que cres!!! se me perdieron, me pasas otra vez las fotos??...") y por último copiarlas a la carpeta destino sin que se repitan los nombres!!!.

Aquí les dejo el programa mencionado (con su respectivo código fuente) y una imagen de guardaFotos 1.0:

viernes, 7 de agosto de 2009

Simulador de flujos

Hace tiempo, bueno un largo tiempo, me tocó realizar una tarea para la clase de Redes (que por cierto no me llamaba tanto la atención como el desarrollo de sistemas), para simular la forma en que se transmiten los datos.

Si no mal recuerdo, estábamos viendo el capítulo 4 del libro de Data Communications and Networking escrito por Behrouz A. Forouzan donde se mencionan las diferentes formas de transmisión (reitero las redes no son mi fuerte): unipolar, polar y bipolar. Dentro de Polar se tienen la formas NRZ-L, NRZ-I, RZ y bifásico --para mayor información pueden consultar el libro en en el capítulo 4--.

En esa ocasión utilicé --para variar-- mi herramienta favorita de desarrollo (Dephi) . Básicamente consiste en pasar a código binario una frase (o teclear directamente la cadena en ceros y unos) y después seleccionar la forma que se quería representar (unipolar, polar, etc).

El programa utiliza el componente TImage para poder dibujar en su canvas y un TScrollBar para poder desplazarse hacia la derecha por aquello de que la fase a "transmitir sea muy grande".

Sin más les dejo el programa con el código fuente y un ejemplo de su ejecución:

tmsgTracking: Miniherramienta para anotar los pendientes de un proyecto

Que tal, seguramente a la hora de desarrollar nuestros proyectos anotamos la lista de pendientes en cualquier lugar hoja de papel (que luego se nos pierde) o si nos va bien en una hoja de cálculo.

Si lo hacemos en la hoja de cálculo luego nos da por ponerle colores, auto filtros, agregamos claves para clasificarlos y si tenemos tiempo (que es raro) una gráfica para ver como vamos, en fin. 

Este programa (con código fuente incluido) nos sirve para llevar el ese control del que hablamos de una forma muy sencilla, sin depender de que tengamos instalado el software de oficina completo. Esta totalmente desarrollado (obvio :D ) en delphi, utiliza clientDataSets, graficos y en el grid se dibujan algunos elementos. Por su tamaño ligero es ideal para guardado en la memoria USB. Espero que sea de utilidad. Puede ser descargado de aquí https://github.com/tmsanchez/ejemplosdelphi/tree/master/tracking

 Aquí unas pantallas:

  • La pantalla principal para dar el seguimiento:
  • Editando el detalle del registro
  • Y por último la gráfica:
Saludos.