Delphi XE2 y Firemonkey (ii) Direct2D y Windows

En post previo sobre Delphi XE2 y Firemonkey expresé mis dudas sobre el uso de Direct2D en Windows previo a Vista.

Como indicara en el mencionado post, la información disponible sobre Firemonkey daba cuenta que en su implmentación para Mac OSX (y iOS? ) usará OpenGL y en Windows usará DirectX para 3D y Direct2D para 2D en plataforma Windows.

Como ya sabemos Direct2D sólo está disponible preinstalado a partir de Windows 7 y disponible en Vista via una actualización. Pero, y en XP (probablemente la base instalada más grande de Windows)???. La pregunta se caía de madura, habrá soporte en esta versión? Asi que le hice la pregunta al propio Andreano Lanusse y la respuesta fue:

Cases where Direct2D is not supported, like Win XP FireMonkey will use GDI+.

Michel Swindell también respondió en el mismo sentido:

on Windows if D2D is not available, FM will use GDI+ for HD vector forms/controls.

Bueno al menos estará disponible, habrá que ver como se comporta ya que GDI+ no es acelerado por hardware, ya que definitivamente las capacidades requeridas para Firemonkey lo hacen inviable con GDI puro.

En un post posterior Andreano Lanusse, contesta las interrogantes surgidas sobre el uso de Firemonkey a través de MS RDP (Remote Desktop), en esta da cuenta de que si el servidor es un un Windows Vista/7  “físico” no tendrá ningún problema ya que estas versiones de Windows soportan 3D en RDP. Si es Wiindows Vista/7 virtualizado en algún entorno sin GPU como XenApp y VmWare ESX, soportará la parte 2D de Firemonkey usando GDI+, la parte 3D se pierde por que no hay una versión de software para estas capacidades. En el caso de un servidor RDP con Windows XP, en esta versión RDP no soporta 3D y la parte 2D como ya dijimos será con GDI+.

Ahora, por que no se usó OpenGL en Windows? pudo ser, pero este no viene preinstalado asi que es una limitante. Además está documentado que los drivers nativos para OpenGL en Windows no son muy pulidos y dan problemas.

DirectX está disponible desde Windows 95, por que no se usó directamente DirectX en lugar de Direct2D para la parte 2D? Bueno me imagino que fue por que hacer 2D con Direct2D es muchisimo más fácil que hacer 2D con DirectX, que si se puede pero la API ya es bastante densa para 3D, usarla para 2D debe ser horrible. Hay que recordar que Direct2D no es si no una capa encima de DirectX. Esto me hace pensar que Embarcadero pudo crear su propia capa 2D, pero realmente seria mucho esfuerzo y encima sujeto a los múltiples mutaciones que Microsoft le ha hecho al DirectX.

Solo nos queda esperar para poder poner a prueba todo el poder de Firemonkey, en todas las plataformas

Anuncios

Delphi XE2 y Multiplataforma

Realmente la nueva versión de Delphi, la XE2, me tiene más que entusiasmado.

Una de las características más saltantes, es en definitiva el soporte multiplataforma.

Delphi no es nuevo en este sentido, ya hace varios años atrás tuvo un ingreso promisorio pero fallido en el terreno de Linux con Kylix, que no era sino Delphi para Linux, toda la IDE completa funcionando sobre esta plataforma. En aquella época la solución a la compatibilidad de entornos gráficos se hizo reemplazando la VCL, que está atada a la API de Windows, con CLX una versión multiplataforma basada en Qt. Sin embargo en ese momento Borland/CodeGear no pudo lograr mantener el producto en el tiempo y finalmente fue dado de baja. Se que hasta hoy hay desarrolladores que siguen trabajando con Kylix, haciendo mantenimiento a software legacy.

Luego de la debacle de Kylix, y como tenía cierta base instalada, surgió un producto llamado CrossKylix, que ofrece desde Delphi para Windows, compilar para Linux usando el compilador por línea de comandos del Kylix. Este tuvo cierta aceptación, pero su creador no fue bien visto a ojos de Borland/CodeGear.

Ya desde el 2008 se vienen escuchando pasos con respecto al soporte multiplataforma. Por supuesto la primera y más obvia petición de los desarrolladores era algo tan sencillo como compilación para Win64, algo que los usuarios de VisualStudio y Java ya gozaban.

En ese momento Delphi toma una decisión interesante: debian cambiar el concepto de su propio compilador, necesitaban un Cross Compiler, es decir que desde el propio Delphi para Windows (x32) se pudiera compilar para diversas plataformas. Es por esto que el soporte para Win64 a demorado tanto tiempo, para que éste encajara en la nueva arquitectura del compilador.

Delphi XE2 viene con esta tecnología de Cross Compiler, ahora uno va a poder programar en el Delphi para Windows de siempre y compilar para:

  • Win32
  • Win64
  • Mac OS X
  • iOS (!!!!)

y producir aplicaciones nativas. Como se ve no hay Delphi para Mac, es el Delphi para Windows compilando para Mac. Nótese que para el caso de Mac y iOS por restricciones (me parece) de Apple es necesario producir el ejecutable final con la herramienta propia de Apple, el XCode, pero sin necesidad de escribir una sola línea en el oscuro Objective-C.

Bajo esta nueva arquitectura la parte visual multiplataforma esta soportada por el nuevo Firemonkey, para poder ver en acción al nuevo Delphi pueden darle una mirada a este video en el blog de Andreano Lanusse:

En el reporte que hiciera Joylon Smith sobre el lanzamiento de Delphi XE2 en Auckland, indica también lo siguiente:

  • Native Android apps – using PhoneGap in RadPHP
  • Native Android apps – to come in the future for Delphi (as well as Linux)

Ajá!!! Con la nueva versión de RadPHP también se podrá compilar para Android, empleando como intermediario PhoneGap, este producto muy interesante permite crear aplicaciones en HTML5 que puedan usar las API nativas de varias plataformas (como Android por ejemplo).

Sin embargo gracias a la tecnología del Cross Compiler, va a ser posible en corto tiempo tener un compilador nativo para Android. Recordemos que si bien la plataforma de desarrollo  de Android es Java, el corazon del robot verde no es si no Linux, y que además Android provee una API para hacer código nativo empleando NDK (Native Development Kit), que es en C o C++.

Mmmm muy interesante, si el Cross Compiler puede generar código nativo para Android y siendo Mac un sobrino de Unix (sus origenes se remontan a FreeBSD y NetBsd), no debería ser ningún problema crear ejecutables nativos para Linux.

Por qué el soporte para Mac llegó antes que el soporte para Linux? bueno acá entramos al terreno de las suposisciones. La mía es primero que Mac tiene desarrolladores más dispuestos a pagar que los de Linux, segundo que Firemonkey (en su encarnación por parte de KSDev) ya estaba maduro en Mac cuando Embarcadero lo adquirió y tercero me parece que hay algunos  desarrolladores en Embarcadero que usan Mac como plataforma principal (aunque trabajan sobre Windows en forma virtualizada).

Se vienen tiempos interesantes para Delphi, el soporte para Mac OS X y especialmente para iOS definitivamente atraerá miradas…

Delphi XE2 y Firemonkey

Bueno, poco a poco van apareciendo más detalles de la nueva versión de Delphi, la XE2.

Ahora tenemos más detalles de Firemonkey y hasta un logo!! FireMonkey-Medium

Andreano Lanusse ha publicado un blog con más detalles interesantes y hasta un par de screenshoots. Por lo que yo entiendo con Firemonkey no tenemos componentes nativos como en la VCL (que seguirá existiendo), si no que todos son dibujados por este framework. Lo bueno de esto es que se consigue libertad absoluta sobre el diseño del control. Otro punto interesante es el soporte en Firemonkey de Styles, que al igual que CSS permitirá crear temas y lo que es mejor aún lograr un look and feel (casi) nativo en cada plataforma, lo cual es muy importante para las aplicaciones para Mac y no herir susceptibilidades. Continúa leyendo Delphi XE2 y Firemonkey

Delphi y UI acelerados por hardware

Tradicionalmente Delphi ha usado las APIs que le provee Windows para dibujar sus controles, es más, los controles propios de Windows son dibujados por el sistema operativo y no por Delphi.

Windows, hasta el Vista usaba GDI para realizar estos dibujos. GDI es una API en C, para gráficos en 2D, es decir líneas, curvas, rectángulos. Internamente esta es la API que usa Windows para dibujar sus controles.  Esta API es rápida pero limitada, ya que no soporta antialiasing, ni transparencias. Sin embargo es muy rápido ya que era (hasta el Windows Vista)  parcialmente “acelerado por hardware”, esto quiere decir que algunas operaciones eran realizadas por el procesador gráfico GPU.

Al salir Windows XP, se creó un nuevo subsistema gráfico llamado GDI+ (GDI plus). Esta API en C++ ofrecía mejoras en la calidad de los gráficos ya que soportaba anitaliasing y transparecias, pero sigue siendo una API para gráficos en 2D. Estas nuevas características son realmente notorias para gráficos de alta calidad, con bordes suavizados tanto en en las lineas y curvas como en el dibujo de las letras (fonts). Sin embargo esta API trabaja integramente por software, es decir no es acelerada por hardware lo que hace que sea mucho más lento que GDI, claro que para gráficos sencillos sin mucha animación como son las interfaces de usuario tradicionales puede no ser muy dramático.

A partir de Windows Vista, Microsoft desarrolló una tecnología diferente para soportar “Aero” que es su nuevo manejador de ventanas “Desktop Window Manager (DWM) composition engine”. Este manejador está basado en DirectX. DirectX es una API de para gráficos 3D y es acelerada por hardware (asumiendo que la tarjeta gráfica soporte DirectX v9, que es el caso de todas las tarjetas modernas). Estas capacidades permiten gráficos de alta calidad usando menos CPU y de forma más rápida.

Continúa leyendo Delphi y UI acelerados por hardware

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.