martes, 24 de febrero de 2009

Una aplicación Desktop / Móvil que se adapta a la pantalla


Este ejemplo hace algo bastante simple, pero útil:

- Detecta el profile en que se está ejecutando (si es una aplicación móvil o de escritorio)
- Dependiendo de eso, obtiene las dimensiones de la pantalla (en caso de ser móvil) o define un tamaño inicial para la aplicación de escritorio.
- En caso de tratarse de una aplicación de escritorio, resta al tamaño de la ventana el borde de la misma, de manera de conocer el area útil (en la que puede desplegar información o gráficos).
- En el caso de una aplicación de escritorio, ajusta lo desplegado al tamaño de la ventana, en caso que se cambie el tamaño a la ventana.



Aquí está el código:

package mobilescreen;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.text.*;
import javafx.animation.*;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

var dx: Number=2;
var dy: Number=3;
var x: Number;
var y: Number;
var realW:Number;
var realH:Number;

var profile = FX.getProperty("javafx.me.profiles");
var isMobile = profile != null and
profile.indexOf("MIDP") >= 0;

var w: Number on replace {
if (w == 0) then w = 300;
realW = w - (if (isMobile) 0 else 16);
x = realW / 2 ;
};

var h: Number on replace {
if (h == 0) then h = 400;
realH = h - (if (isMobile) 0 else 36);
y = realH / 2 ;
};

Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames: [
KeyFrame {
time: 0.02s
action: function () {
x += dx;
y += dy;
if (x < 0 or x > realW )
dx = -dx;
if (y < 0 or y > realH)
dy = -dy;
}
}
]
}.play();

Stage {
width: bind w with inverse
height: bind h with inverse
scene: Scene {
content: [
Text {
font: Font { size: 16 }
x: 10, y: 30
content: bind
"width: {w}\nheight:{h}\nis mobile: {isMobile}"
},
Rectangle {
x: 10, y: 10
width: bind realW - 20
height: bind realH - 20
fill: Color.BLUE
opacity: 0.5
},
Circle {
centerX: bind x,
centerY: bind y
fill: Color.RED,
opacity: 0.5
radius: 40
}
]
}
};

lunes, 23 de febrero de 2009

Cómo crear una aplicación móvil con JavaFX y Netbeans 6.5


Este video muestra lo sencillo que es crear y probar aplicaciones móviles desarrolladas en JavaFX script con Netbeans 6.5.

Básicamente, sólo tienes que crear una aplicación y luego indicar que la vas a ejecutar con el emulador.

lunes, 16 de febrero de 2009

Como reemplazar y centrar textos incrustados en archivos Adobe Illustrator con JavaFX


Uno de los beneficios de crear gráfica para JavaFX con Adobe Illustrator, es que luego esta puede ser reemplazada sin necesidad de alterar el código. Esto permite cambiar rápidamente la apariencia de una aplicación o dotarla de "pieles" o "skins" (distintas apariencias, a elección del usuario). Estas plantillas, que permiten incluso cambiar la posición de los elementos en la interfaz de usuario, entre otras cosas, pueden contener textos, que son posibles de reemplazar (haciendo su contenido dinámico).

Pero, para hacerlo hay un par de detalles que es necesario conocer.

Primero crearé una plantilla con Adobe Illustrator:



Una vez generado el archivo .FXZ podemos analizar el código.

Sólo me concentraré en la manipulación de textos, ya que en artículos anteriores he mostrado como trabajar con otro tipo de elementos gráficos generados con Adobe Illustrator.

Primero, crearemos una clase que cargue el archivo gráfico (.fxz) y que obtenga de él los nodos con los objetos.


import javafx.scene.Node;
import javafx.fxd.UiStub;
import javafx.scene.text.*;

public class gaugeui extends UiStub {

override public var url = "{__DIR__}gauge.fxz";

public var reflex: Node;
public var needle: Node;
public var decoration: Node;
public var body: Node;

public var dispvalue: Text;
public-read var dispvaluew;
public-read var dispvaluex;

override protected function update() {

reflex = getNode("reflex");
needle = getNode("needle");
decoration = getNode("decoration");
body = getNode("body");

dispvalue = getNode("dispvalue") as Text;
dispvaluew = dispvalue.boundsInLocal.width;
dispvaluex = dispvalue.boundsInLocal.minX;

}
}

Revisemos el código:

override public var url = "{__DIR__}gauge.fxz";

Esa línea indica desde donde debe descargar el archivo con la gráfica: {__DIR__} apunta al mismo directorio que la aplicación;

public var reflex: Node;
public var needle: Node;
public var decoration: Node;
public var body: Node;

Declara algunas variables para contener otros elementos gráficos;

public var dispvalue: Text;
public-read var dispvaluew;
public-read var dispvaluex;

Declara una variable (dispvalue) de tipo TEXTO, para obtener el nodo que contiene el texto que vamos a reemplazar en este ejercicio, y dos variables adicionales asociadas a ese texto: una (dispvaluew) que contendrá el ancho del area reservada originalmente para el texto y otra (dispvaluex) que contendrá la posición horizontal original para el área de texto;

override protected function update() {

// obtiene los nodos graficos
reflex = getNode("reflex");
needle = getNode("needle");
decoration = getNode("decoration");
body = getNode("body");

// obtiene el nodo, pero lo transforma en texto
dispvalue = getNode("dispvalue") as Text;

// obtiene el ancho del texto original
dispvaluew = dispvalue.boundsInLocal.width;
// obtiene la posicion horizontal original del texto
dispvaluex = dispvalue.boundsInLocal.minX;

}


Para rescatar los nodos desde el archivo .fxz, utilizamos los nombres de asignamos a los elementos en el diseño. En nuestro ejemplo, llamamos al elemento de texto que deseamos manipular "jfx:dispvalue" (la identificacion jfx: permite identificar las etiquetas de nodos que importará JavaFX), y por lo tanto, obtenemos ese nodo con un getNode("dispvalue"), e inmediatamente lo convertimos en un Text (as Text).

Ahora bien, uno de los inconvenientes de la modificación de los textos desde un script, es que al modificar el contenido, se modifica el ancho del elemento que contiene el texto, y dependiendo de la alineación también puede modificarse la posición horizontal.

Por eso, al obtener el nodo de texto original, también almaceno la posición (dispvaluex) y el ancho (dispvaluew) que tenía el texto en el diseño. Con esta información más la nueva información de ancho generada al modificar el contenido del texto, puedo calcular la posición centrada del texto.

Para conseguirlo, puedo hacer algo como esto:

// instancia la clase que carga la gráfica (arriba)
var ui = gaugeui{};

// variable (degree) que mostrará en el area de texto
var degree = 0.0 on replace {

// actualiza contenido con numero entero convertido en string
ui.dispvalue.content="{degree as Integer}";

// obtiene nuevo ancho del texto (alterado por nuevo contenido)
var w = ui.dispvalue.boundsInLocal.width;

// calcula coordenada horizontal para mantener el texto
// centrado respecto a su posicion original en el diseño
ui.dispvalue.x = ui.dispvaluex +
ui.dispvaluew / 2 - w / 2;


};


Al modificarse degree, obtiene su valor entero y lo convierte en un string. Esto lo hace al incluir la variable como parte de una cadena de texto entre paréntesis de llave... "{expresión}"

A continuación, obtiene el nuevo ancho del texto modificado, con un: elemento_texto.boundsInLocal.width

Finalmente, obtiene la nueva posición horizontal del texto, usando la posición original del texto en el diseño mas la mitad del ancho del texto original. En este punto sabemos cual era el punto medio del texto original (posición respecto a la cual centraremos el nuevo texto).

A esa posición, restamos la mitad del nuevo ancho del texto.... y como resultado, el texto se mantiene visualmente centrado.



La inconveniente con el uso de TextAlignment.CENTER, es que el texto se centra respecto a las demás líneas de un párrafo (con más de una línea), entonces, si usamos un texto con una sóla línea, TextAligment.CENTER no tiene ningún efecto.

En resumen, hay que recuperar el nodo del texto por su nombre, convertilo y almacenarlo como Text, obtener el ancho y posición original del texto en el diseño... y calcular la posición horizontal del texto al modificar su contenido.

Por cierto, es posible exportar los archivos Illustrator a .fxz sin los fonts, pero si te quieres asegurar que los textos se mantendrán en apariencia, tamaño y posición, es mejor incluirlos. El resultado no es extremadamente grande, un font típico pesa cerca de 50KB.

Ojalá esto sea de utilidad.

domingo, 15 de febrero de 2009

Como hospedar Aplicaciones Java Web Start en Google App Engine


Estaba buscando donde hospedar un par de demos Java Web Start y finalmente recordé que tenía una cuenta de Google App Engine, así que me puse a investigar como hospedar allí los archivos JNLP y JAR de mis aplicaciones.

Hacerlo no resulta obvio, pues Google App Engine no ofrece un acceso de tipo FTP o un upload de archivos via web. La manera de hacerlo es sincronizando una aplicación Python local con los servidores de Google utilizando el utilitario appcfg.py update path/nombre_aplicacion_local, y la forma de subir los contenidos estáticos es incluirlos como parte de la aplicación Python y configurar la aplicación para servir contenidos estáticos e incluir una definición del MIME type para los archivos JNLP, de manera que sean bien interpretados por los navegadores (IE 7 despliega el contenido del archivo JNLP en vez de lanzar la aplicación, si el servidor no está configurado con el tipo JNLP entre los tipos servidos).

La solución final fue esta (creo que hay otras, pero esta fue la que me funcionó y no quise gastar más tiempo en investigar ;D):

- Creé dos subdirectorios como parte de una aplicación Python, en la ruta demos en mi copia local de Google App Engine... los llamé /exec y /jfx

- En el directorio /jfx copié los archivos JNLP

- En el directorio /exec copié los archivos JAR con mis aplicaciones JWS

- Luego, configuré el archivo app.yaml en el raíz de mi aplicación Python, de la siguiente manera:

application: javafxdemo
version: 3
runtime: python
api_version: 1

handlers:
- url: /exec
static_dir: exec

- url: /jfx
static_dir: jfx
mime_type: application/x-java-jnlp-file

- url: .*
script: javafxdemo.py

Finalmente, ejecuté el comando: appcfg.py update demos\javafxdemo ... que sincronizó el directorio local con la aplicación en Google App Engine.

Previamente modifiqué los archivos JNLP, de manera de explicitar que los archivos JNLP y los JAR están en directorios separados. Así que alteré las siguientes líneas:

<jnlp spec="1.0+" codebase=
"http://javafxdemo.appspot.com/"
href="jfx/Knob.jnlp">


...

<jar href="exec/Knob.jar" main="true"/>

Espero que les sirva este dato (por lo menos me servirá de ayuda-memoria la próxima)... o que me digan donde puedo hospedar (gratuítamente) contenidos estáticos sin tanto jaleo! jaja! y con 10GB de tráfico de salida gratuito ;D

Saludos.

Stage Controller, almost 1000 downloads - Casi 1000 visitas para descargar el Stage Controller


Almost 1000 people visited the blog in a day to download the Stage Controller class. Thanks to all of you for your interest.

La verdad me sorprendió, pero casi 1000 personas visitaron el blog en un día para descargar el componente que controla los Stage... :D ... Visitas desde Nigeria, China, India, EEUU, Brazil, etc. Se ve que JavaFX está consiguiendo una comunidad global de desarrolladores, ¿no?


Gracias a todos por su interés.

sábado, 14 de febrero de 2009

My Google Code: Knob & Stage Controller / Perilla y controlador de Stage


Two of the components I developed are now hosted at Google Code. They include documentation about how to use them.

Dos de los componentes que desarrollé están ahora hospedados en Google Code. Ellos incluyen la documentación sobre como usarlos.

Knob control / Perilla
http://code.google.com/p/javafxknob/
Java Web Start demo

Stage Controller / Controlador de Stage
http://code.google.com/p/javafxstagecontroller/
Java Web Start demo

JavaFX 1.1 liberado (incl. JavaFX Mobile)


Fue liberada la versión 1.1 de JavaFX, que incluye el primer release de JavaFX Mobile.

Ahora los programas desarrollados con JavaFX de escritorio corren sin modificación en JavaFX Mobile, a diferencia -por ejemplo- de Flex, que tiene su propia versión para móviles, FlexLite.

http://www.javafx.com/launch/


El SDK 1.1 incluye un emulador que permite probar que tal funciona la portabilidad escritorio -> móvil

También, a primera vista, se ven algunos detalles de mejor integracion con Netbeans 6.5, como algunos elementos en la paleta de componentes.

jueves, 12 de febrero de 2009

JavaFX: Stage "controller" demo - Demo "controlador" de Stage


This small code demostrates how easy is to handle the onResize and onMove events implemented by the Stage controller (Stage Controller).

Este pequeño código demuestra lo fácil que es manejar los eventos onResize y onMove implementados por el controlador de Stage (Controlador de Stage)



Here's the code / Aquí está el código:

var img = Image { url: "{__DIR__}myimage.jpg" };
var rect:Rectangle;
var sw:Integer;
var sh:Integer;

var cs = controlStage {
timeToCallFunctions:0.001s
timeToCheckPosSize:0.001s
initialPosition:controlStage.CENTER, persist:true
checkMinWidth:true, minWidth:270,
checkMinHeight:true, minHeight:270,
stickyBorders:true
onResize: function(e) { clip(e) }
onMove: function(e) { clip(e) }
};

// screen resolution
sw = cs.maxScrWidth;
sh = cs.maxScrHeight;

function clip(r:Rectangle2D) {
rect = Rectangle {
x: r.minX - (sw - img.width) / 2
y: r.minY - (sh - img.height) /2
width: r.width, height: r.height
}
};

Stage {
width: bind cs.width with inverse
height: bind cs.height with inverse
x: bind cs.x with inverse
y: bind cs.y with inverse
onClose: function() { cs.persistStage() };

scene: Scene { content:
ImageView {
translateX: bind -rect.x
translateY: bind -rect.y
image: img
clip: rect
}
}
};



Download the Netbeans 6.5 project, here. Descarga el proyecto Netbeans 6.5, aquí.

viernes, 6 de febrero de 2009

JavaFX: A Stage "controller" / Un "controlador" de Stage


Update: Stage Controller hosted on Google Code, includes documentation for using the class. Click Here for a Java Web Start example.



This class allows you to "attach" some automatic behaviors to your app window (Stage). For example, you can make the window to stick to the edges of the screen with a simple... stickyBorders:true ... or select the borders you want to make sticky... ie. stickyLeft:true

You can persist the position and/or size of the window (with a simple persist:true, persistPosition:true or persistSize:true). You can anchor the window to the borders too (ie. anchorBottom:true). Enforce minimum and maximum sizes or enforce a specific size for the window or keep it in the middle of the screen, etc.

It can trigger two events: onResize and onMove... so, your app can obtain it screen position and size at any moment (demo, handling events).

There are many options and combinations.

Enjoy it ;)

Actualización: Ahora el Controlador de Stage es capaz de mantener la posición y/o tamaño de la ventana de la aplicación entre sesiones.

Esta clase permite definir comportamientos automáticos para la ventana de tu aplicación. Por ejemplo, puedes hacer que la ventana se "pegue" a los bordes de la pantalla con un simple... stickyBorders:true ... o seleccionar los bordes que quieres que sean "pegajosos"... ej. stickyLeft:true

Puedes hacer que la aplicación recuerde su posición y/o tamaño entre sesiones de uso (con un simple persist:true, persistPosition:true o persistSize:true). Puedes "anclar" la ventana a los bordes también (ej. anchorBottom:true). Forzar tamaños mínimos y máximos o un tamaño específico para la ventana... o mantener la ventana en el centro de la pantalla.

También puede gatillar dos eventos: onResize (si cambia el tamaño de la ventana) y onMove (si cambia de posición la ventana en la pantalla)... de esa manera la aplicación puede saber -en todo momento- en que área de la pantalla está localizada o que tamaño tiene (demo, manejando los eventos).

Hay muchas opciones y combinaciones.

Ojalá sea útil ;)

How to use it / Cómo se usa...
/** Stage controller */
var cs = controlStage { //persistFile: "testStage.persist"
initialPosition:controlStage.RIGHT + controlStage.TOP, persist:true
checkMinWidth:true, minWidth:440, checkMinHeight:true, minHeight:270,
stickyBorders:true


onResize: function(e):Void {
println("resize to {e.width},{e.height} at {e.minX},{e.minY}");
}
onMove: function(e):Void {
println("moved to {e.minX},{e.minY} with {e.width},{e.height}")
};


};

Stage {
// bind Stage (window) to the controller
width: bind cs.width with inverse
height: bind cs.height with inverse
x: bind cs.x with inverse
y: bind cs.y with inverse


// on stage close, stores last position and size
onClose: function() { cs.persistStage() };

scene: Scene { ....





Descargar el proyecto Netbeans 6.5.... DOWNLOAD the Netbeans 6.5 project.... CLICK HERE

miércoles, 4 de febrero de 2009

Curso gratuito de JavaFX Script, de 15 semanas de duración


A partir del 30 de Enero pasado, se inició un curso gratuito por internet, para aprender JavaFX Script. Una vez por semana, los autores (Jim Weaver** & Sang Shin) publican el material necesario para experimentar y estudiar el lenguaje.

Solo tienen que mirar una vez por semana este sitio, al final del curso los participantes recibirán un diploma por su participación (aunque simbólico mas que nada, porque no es respaldado por ninguna institución):