Dibujando con Delphi (2 – GDI)

La mayoria de los controles visuales de Delphi incluyen un Canvas sonre el que éstos están dibujados.  Muchos controles exponen su propiedad Canvas como Public y otros a través de eventos como OnPaint o CustomDraw o parecidos.

Vamos a ver ahora el ejemplo más fácil de dibujo usando el Canvas del control TPaintBox (en la paleta System). El objeto Canvas de Delphi tiene un conjunto de Propiedades y Métodos que nos permitirán dibujar Línes, Círculos, Rectángulos usando colores y colores de borde.

Coloquemos un control TPaintBox en nuestro formulario y fijemos su tamaño (Height y Width) en 150 x 150. Con el control seleccionado veamos sus Eventos y ubiquemos el evento OnPaint, doble click para entrar a su implementación, luego agreguemos el siguiente código:

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
 // Fijamos el Color del Brush (el relleno) en verde
 PaintBox1.Canvas.Brush.Color := clGreen;
// Dibujamos un rectángulos desde las coordenadas 10,10 hasta las coordenadas 60,60
 PaintBox1.Canvas.Rectangle(10, 10 , 60, 60);

 // Cambiamos el color del Pen (el borde) a rojo
 PaintBox1.Canvas.Pen.Color := clRed;
 // y fijamos el ancho del la linea de borde a 4 pixeles
 PaintBox1.Canvas.Pen.Width := 4;
 // El color del Brush (relleno) lo ponemos a amarillo
 PaintBox1.Canvas.Brush.Color := clYellow;
 PaintBox1.Canvas.Rectangle(40, 40 , 100, 100);

 // Dibujamos un círculo
 PaintBox1.Canvas.Ellipse(50, 50, 20, 20);
end;

y obtendremos eun resultado como el siguiente:

Muy fácil!! Ahora fijemonos en algunos detalles:

  • Al dibujar el primer rectángulo,  las características del Pen (borde) se dejaron con los valores por defecto (negro, 1 pixel).
  • Al dibujar el círculo se usaron los valores fijados anteriormente tanto para el Pen como para el Brush.

Esta últma observación quiere decir que si no decimos lo contrario se usarán los últimos valores fijados para el canvas.

Otra observación es que el evento OnPaint del control TPaintBox se lanza cada vez que el control deba redibujarse, esto sucede cuando por ejemplo ocultamos la ventana con otra ventana y luego la volvemos a mostrar. Si haces la prueba notarás que el dibujo a cambiado y ahora se ve así:

¿Por qué el borde del primer rectángulo cambió a rojo y es más grueso? La respuesta es que el evento OnPaint se volvió a lanzar y volvió a hacer el dibujo, sólo que las propiedades de Pen han quedado con los últimos valores que le dimos. Para evitar este efecto debes asegurarte de fijar los valores de Pen y Brush tal como quieres que se vean, es decir debimos fijar el color del Pen a clBlack y el Width del Pen a 1 antes de dibujar el primer rectángulo.

Si quieres forzar el repintado de un control puedes llamar al método Invalidate del control, por ejemplo cuando quieres cambiar programáticamente algún color.

Bueno eso es lo básico del Dibujo usando el Canvas, algunos usos interesantes son:

  • Crear tus propios controles con diseños propios.
  • Cambiar los colores en las celdas de una grilla, por ejemplo poner las filas impares de otro color, o los valores negativos con fondo rojo, dibujar indicadores especiales, etc

Más adelante veremos de hacer algunos ejemplos de éstos.

Delphi y XML (y 3)

Para terminar con XML vamos a ver como nos podemos pasear por los nodos del documento.

Para este ejemplo vamos  usar un ejemplo un poco más extenso que los usados anteriormente:

<libros>
  <libro tipo="novela">
    <nombre>La casa verde</nombre>
    <autor>Mario Vargas Llosa</autor>
  </libro>
  <libro tipo="novela">
    <nombre>Un mundo para Julius</nombre>
    <autor>Alfredo Bryce Echenique</autor>
  </libro>
</libros>
</pre>

A continuación vamos a listar todos los elementos <libro> hijos del elemento <libros> y mostraremos el nombre y el autor de cada uno.

<pre>procedure TForm1.Button2Click(Sender: TObject);
var
  ANode: IXMLNode;
  I: integer;
  CadenaLibro,
  CadenaSalida: string;
begin
  for I := 0 to XMLDocument1.DocumentElement.ChildNodes.Count - 1 do begin
    ANode := XMLDocument1.DocumentElement.ChildNodes[I];
    if ANode.NodeType = ntElement then begin
      CadenaLibro := ANode.ChildNodes['nombre'].Text + ' - ' + ANode.ChildNodes['autor'].Text;
      CadenaSalida := CadenaSalida + CadenaLibro + #13#10;
    end;
  end;
  ShowMessage(CadenaSalida);
end;

Algunas observaciones:

  • Si inspeccionamos el valor de XMLDocument1.DocumentElement.ChildNodes.Count nos devuelve el valor de 7, a pesar de solo haber agregado 2 nodos!! Si vamos al detalle descubriremos que lo 5 nodos extras tienen la propiedad NodeType igual a ntText y los 2 que nos interesan son de tipo ntElement. ¿Por qué se agregaron esos nodos de texto (en blanco por cierto)?. Es por que hemos puesto la propiedad Options/doNodeAutoIndent en True. Esto hace que internamente se agregen los saltos de línea y los espacios en blanco de la indentación. Si ponemos este valor a False y volvemos a hacer la prueba veremos que nos devuelve sólo 2 elementos.
  • Notemos que podemos referenciar los nodos hijos en ChildNodes tanto por su índice como por su nombre.
  • Finalmente, aunque creo que ya es obvio a este punto, XML sólo maneja texto y sólo texto, es decir que si queremos guardar el valor 125.56 tendremos que hacerlo como cadena, igualmente al momento de recuperarlo será como cadena y luego habrá que convertirlo al tipo correcto. Esto no quiere decir que no exista forma de guardar data binaria en un documento XML. Para poder hacer esto deberíamos primero codificar esta data binaria en algún formato de sólo texto como por ejemplo Base64 , UUEncode o algún otro.
  • XML sigue las mismas reglas que HTML sobre el uso de caracteres especiales, por lo que no se puede agregar directamente como texto caracteres como < ó >.

Otras funciones que nos permiten recorrer los elementos del documento son PreviousSibling y NextSibling así como ParentNode.

Delphi 2010 y XML (2)

Siguiendo con el tópico de XML veamos ahora algo de código. Como ejemplo tomaremos la estructuta XML del post anterior y lo crearemos por código.

A la hora de trabajar con documentos XML lo podemos hacer creando una instancia de la clase TXMLDocument o usando el control del mismo nombre que encontraremnos en la paleta de controles bajo Internet.

Un par de cosas antes de continuar, un nodo como por ejemplo <libro> se denomnina elemento, en XML todos lo que se crean son nodos, elemento por ejemplo es un tipo especial de nodo, un atributo también es un tipo de nodo, el contenido de un elemento tambien es un tipo de nodo.

Creemos una ventana como la que sigue para hacer nuestras pruebas:

Elijamos el  control creado y en la venatana de Propiedades podemos ver una llamada DOMVendor, en ella podremos elejir entre las disponibles, actualmente MSXML, Xerces y ADOM. Cual elejimos? depende de nuestras preferencia y el uso que le demos, si no sabes cual, apunta a lo seguro (¿?) y elije MSXML de Microsoft. Para fnes de este ejecicio expandimos la propiedad Options y ponemos a True doNodeAutoIndent, esto permitira que el texto que obtengamos aparezca indentado para ver mejor la jerarquía (esto es opcional, el formato XML no rquiere indentación e incluso todo el texto puede ir en una sola línea).

Ahora en el evento OnClick de nuestro botón agregaremos algo de código para crear la estructura planteada:

procedure TForm1.Button1Click(Sender: TObject);
var
DatoNode,
LibroNode,
RootNode: IXMLNode;
XMLString: string;
begin
XMLDocument1.Active := True;                // Debemos activar el Documento para poder trabajar
RootNode := XMLDocument1.AddChild('libros');  // Creamos el nodo raíz
LibroNode := RootNode.AddChild('libro');      // Agregamos un elemento debajo de raíz
LibroNode.Attributes['tipo'] := 'novela';     // Le agregamos un atributo a nuestro elemento
DatoNode := LibroNode.AddChild('nombre');     // Agregamos 2 nodos debajo del elemento Libro
DatoNode.Text := 'La Casa Verde';
DatoNode := LibroNode.AddChild('autor');
DatoNode.Text := 'Vargas Llosa';

XMLDocument1.SaveToXML(XMLString);            // Grabamos el documento en texto
Memo1.Text := XMLString;                      // y lo mostramos
end;

Ejecutemos el programa y obtendremos el siguiente resultado al hacer click en el boton.

En la línea 17 he usado XMLDocument1.SaveToXML(var XML: String) que toma la estructura creado y la convierte en texto. Del mismo modo pude haber usado SavetoFile() que grabariá el contenido en un archivo.

Lo mismo podemos hacer si usamos LoadFromXML() ó LoadFromFile().

Bueno eso es todo por ahora. En el siguiente post veremos como recorrer el Documento XML y obtener valores.

 

 

 

 

Delphi y XML (1)

XML que significa eXtenible Markup Language (lenguaje de marcas extensible) es para mi, muy a pesar de su nombre, no un lenguaje si no un formato para representar data/información arbitraria (por eso lo de extensible).

XML al igual que HTML son derivados de un concepto más genérico llamado SGML, por lo que comparten los conceptos jerárquicos así como la idea de tags o etiquetas, de ahi que ambos se vean muy parecidos a simple vista.

XML a cobrado notoriedad desde hace algunos años atrás como una forma muy legible (para humanos) de representar casi cualquier tipo información, al ser puramente texto con reglas explícitas para manejar caracteres especiales y no imprimibles, lo hace muy fácil de transportar entre plataformas y lenguajes.

XML tiene la particularidad de poder almacenar tanto la información en sí, como meta-información en la forma de tags y atributos, por ejemplo:

<libros>
  <libro tipo="novela">
    <nombre>La casa verde</nombre>
    <autor>Mario Vargas Llosa</autor>
  </libro>
</libros>

Como se ve no es necesario conocer la intención del autor para saber de que se trata. Es bastante autodescriptivo, incluso se puede notar la jerarquía entre los elemetos.

Estas características lo hacen muy interesante como medio de almacenar y transportar información entre sistemas diferentes, en plataformas diferentes o lenguajes de programación distintos. Sin embargo tanta maravilla no es gratis. La información así descrita ocupa mucho más espacio que otros formatos binarios, la tarea de “parsear” la información tanmbién es más pesada. La carga para el humano lector es más fácil, pero para la máquina es más costoso, claro que para eso están las máquinas, para reducir nuestro esfuerzo.  NOTA: Estas consideraciones deberían tomarse en cuenta cuando se transmite grandes volumenes de información y/o el tiempo de procesamiento debe ser mínimo.

Delphi puede manejar XML usando diferentes mecanismos. Delphi 2009/2010 incluye al menos 3 motores distintos, versiones previas usan el Microsoft MSXML, aunque también hay varios componentes de terceros, algunos comerciales y otros free.

En Delphi 2010 se incluyen:

  • MSXML, de Microsoft que usa la Msxml.dll
  • Xerces, es una librería escrita en C++, que es parte del proyecto Apache.
  • ADOM, Alternative Dom, que es una nueva versión de OpenXML, escrita integramente en Delphi por lo que no depende de ninguna librería externa.

Todas ellas permiten crear Documentos XML, cargar un Documento XML desde un archivo, grabrlo a un archivo, recorrerlo, y hacer búsquedas.

Para entender como se trabaja con XML debemos conocer algunos conceptos primero:

  • Un Documento XML está formado por un conjunto de nodos, organizados jeráquicamente.
  • Un nodo tiene una etiqueta o tag, puede tener atributos, y puede tener un contenido.
  • Un nodo esta limitado por una etiqueta de inicio y una de fin.
  • Un Docuemento XML tiene un solo nodo raíz, a partir del cual se arma toda la jerarquía.

Por ejemplo si el pedazo de código de líneas arriba es un documento XML entonces diriamos que:

<libros>

Es el nodo raíz, este nodo tiene una etiqueta de inicio que es “<libros>” y una etiqueta de fin que es “</libros>”

  <libro tipo="novela">

Este nodo tiene por etiqueta o tag <libro> , vemos que además tiene un atributo llamado tipo y cuyo valor es novela.

Finalmente en el siguiente nodo:

  <nombre>La casa verde</nombre>

Es un nodo de tag <nombre> y que tiene un contenido que es “La casa verde”.

Ya me cansé por hoy así que acá lo dejo.

En la siguiente entrada veremos código de como se maneja XML en Delphi.

Delphi y Bases de Datos

Delphi ha sido tradicionalmente una herramienta excepional para trabajo con bases de datos, su propio nombre fué elejido como la herramienta para trabajar con Oracle (The Oracle at Delphi), de esto yá hace muchísmos años.

A lo largo del tiempo la forma en que Delphi trabaja con Bases de Datos ha ido variando.  La tecnología que Delphi promueve actualmente para su uso en desarrollo es DBX (dbExpress). Sin embargo no es la única ya que también soporta componentes de conexión nativos (conexiones directas a la BD o usando el protocolo nativo de la BD), ODBC y ADO.

Desde la época de Borland, Delphi viene con Interbase siendo esta la BD por default.  Interbase tiene en Firebird a su vástago OpenSpurce. Interbase/Firebird es una BD madura de nivel comercial que lleva varios años de delantera sobre muchas BD usadas en la actualidad (incluídos mySql, Postgres).

Delphi puede usarse con una amplia variedad de Bases de Datos comerciales y libres que se usan en la actualidad por ejemplo:

Además existen motores de bases de datos embebidos (incrustados) que pueden usarse con Delphi. Esotos motores pueden usarse para replicación local en aplicaciones Cliente/Servidor, para almacenamiento temporal, o cuando se requiera aplicaciones autocontenidas sin dependencias externas. Entre los más conocidos tenemos:

  • SQLite , usando la dll propia de SQLLite, existe tambien ports completos a Delphi
  • NexusDB, compila directamente en el EXE.
  • elevatedb,  compila directamente en el EXE.
  • Absolute Database, compila directamente en el EXE.
  • Firebird, usando una dll.
  • Accuracer Database,  compila directamente en el EXE.

Otra forma de manejar datos es usando tablas en memoria (Memory tables), muy útil para datos temporales:

Como se ve Delphi posee un arsenal muy completo para atacar el desarrollo de aplicaciones de Base de Datos, tal es así que algunas herrmientas para BD están desarrollados en Delphi, por ejemplo: