Mostrando entradas con la etiqueta como. Mostrar todas las entradas
Mostrando entradas con la etiqueta como. Mostrar todas las entradas

viernes, 24 de abril de 2009

Demo de TextHTML (componente de memeFX)


Aquí hay una pequeña demo del componente TextHTML en acción. Incluido el uso de LINKS en los textos de una aplicación JavaFX. También pueden ver AQUI una demo Java Web Start.



La biblioteca memeFX está AQUI

sábado, 18 de abril de 2009

Como mejorar la partida de Java Web Start


Aquí hay un truco para mejorar la velocidad de partida de las aplicaciones JavaFX Web Start.

Todo lo que necesitas hacer es agregar una linea a tus archivos JNLP.

<update check="background">

El elemento update se usa para indicar la preferencia sobre como Java Web Start maneja las actualizaciones. El elemento update puede contener los siguientes atributos opcionales:

Atributo check: El atributo check indica la preferencia sobre cuando el cliente JNLP debe chequear por actualizaciones, y puede tener uno de los siguientes tres valores:

1. "always": Siempre chequea por actualizaciones antes de lanzar la aplicación.
2. "timeout" (default): Chequea por actualizaciones hasta alcanzar un umbral de tiempo (timeout) antes de lanzar la aplicación. Si el chequeo de actualización no se completa antes del timeout, la aplicación es lanzada, y el chequeo de actualización continua por "atras" del proceso de la aplicación.
3. "background": Lanza la aplicación mientras chequea si existen actualizaciones simultaneamente, por "atras".

La opción 3 mejorará el tiempo de partida de las aplicaciones JavaFX Web Start.

jueves, 16 de abril de 2009

Un detalle para obtener una mejor performance


Este detalle (junto con incluir canSkip:true en los timelines asociados a animaciones o transiciones gráficas de algún tipo) puede hacer una gran diferencia en la performance gráfica de JavaFX.



Tengo un CustomNode cuyo contenido son unos nodos almacenados en una secuencia:


public class myComponent extends CustomNode {

var objs:Node[];

public override function create(): Node {
Group {
content: bind objs
};
};
}

Digamos que se necesita reemplazar con frecuencia los nodos en objs y que tengo una función que realiza este trabajo:

function paint():Void {

delete objs;

for (element in someGroup) {
...
insert newNode into objs;
...
}
}

Como muestra el video, eso es ineficiente. Al estar enlazado el contenido de objs con el contenido del componente e ir cambiando el contenido de objs, se va gatillando trabajo para refrescar el componente.

Es más eficiente crear una secuencia temporal y traspasar al final todos los nodos a la secuencia asociada al componente:

function paint():Void {

var tmpObjs:Node[];

for (element in someGroup) {
...
insert newNode into tmpObjs;
...
}

objs = tmpObjs;
}

Habría que probar si esto también es aplicable cuando se realizan cambios a los elementos en la secuencia (y no sólo cuando estos se reemplazan). Es probable que ocurra lo mismo, porque al actualizar uno a uno los elementos, es muy probable que también se vaya gatillando trabajo parcial, mientras si se reemplaza toda la secuencia de una vez, ese trabajo debería ocurrir una sóla vez... ¿?

martes, 14 de abril de 2009

Un "truco" para obtener el alto de un Font


Estoy construyendo un componente de texto HTML para mi librería de JavaFX, y me encontré con el siguiente problema.

¿Cómo obtengo el alto de un font?

No confundan el obtener el alto de un TEXT con obtener el alto de un FONT.

Si uno tiene un texto y quiere obtener sus dimensiones, basta con:


var myText = Text {
content: "Mi texto"
...
Font {
size:24
...
}
}

var ancho = myText.boundsInLocal.width;
var alto = myText.boundsInLocal.height;


El asunto es que si uno pone "....." como contenido del texto, el alto es de apenas unos pixeles.

Probablemente ustedes no se vayan a encontrar con este problema con mucha frecuencia, pero para el componente que estoy creando es decisivo... entonces, aquí va una solución bastante... mmm.... "simple"... pero funciona.


var myFont = Font {
size=24
...
}

var tmpText = Text {
content: "Aj"
font: myFont
}

var myText = Text {
content: ".........."
font: myFont
...
}

var altoFont = tmpText.boundsInLocal.height;
var anchoTexto = myText.boundsInLocal.width;


No es el ideal recurrir a este tipo de "trucos", pero me pareció mejor que tener que incluir las APIs de Java para el manejo de Fonts, que si entregan todo tipo de información sobre las fuentes... espero que en próximas versiones de JavaFX la API incluya una alternativa más "elegante", es decir, que entregue directamente las medidas asociadas a las fuentes.

martes, 7 de abril de 2009

Cómo compilar clases Java en JavaFX, que contienen delete o insert


Como saben, los términos "insert" y "delete" están reservados por JavaFX para insertar y borrar elementos en las secuencias. Esto puede producir un inconveniente cuando uno incluye dentro de un proyecto JavaFX una clase Java donde se utiliza llamadas a métodos denominados "insert" o "delete".

Esto ocurre, por ejemplo, si se utiliza "delete" para borrar un archivo. El compilador muestra el siguiente error:

Sorry, I was trying to understand an expression
but I got confused when I saw 'delete' which is a keyword.
new java.io.File("temp").delete();
^

La solución es simple, sólo hay que incluir el término entre << ... >>

new java.io.File("temp").<<delete>>();

Lo interesante es que esta sintaxis permite utilizar cualquier texto como un identificador:

def <<english
variable>> = "cualquier simbolo sirve como identificador";
def <<русская переменная>> = <<english
variable>>;
println(<<русская переменная>>);

La salida del script es:

cualquier simbolo sirve como identificador

Noten que el identificador "english variable" incluso incluye un salto de línea (CR/LF).

lunes, 30 de marzo de 2009

Usando FX.deferAction()


Al desarrollar el componente de acordeón de imágenes, se producía un "pestañeo extraño" al momento de solicitar a los elementos que actualizaran su posición. Le dí algunas vueltas al código hasta comprobar que: no era resultado de algo producido por un error en el código, sino por algo relacionado con el refresco de la pantalla (o algo por el estilo ¿?).

Así que recurrí un poco al instinto y a la memoria... y... recorde haber leido algo sobre deferAction. Así que incluí el código que solicita el ajuste de posición, dentro de la llamada de esta función y el problema terminó:

El siguiente código:


public-read var active: Integer on replace {
for (item in pictures) {
item.adjust();
};
};



Pasó a ser este:


public-read var active: Integer on replace {
FX.deferAction(function():Void {
for (item in pictures) {
item.adjust();
};
});
};



Sólo anidé el for dentro de FX.deferAction(function():Void { ... });

Sí descargan la biblioteca memeFX y quitan el FX.deferAction en ImagesAccordion.fx, quizás puedan ver el problema que me llevó a esta solución (no sé si el problema sea reproducible en otras máquinas). Tampoco me quedó claro que produce el problema ni por qué lo resuelve deferAction, voy a buscar información al respecto. Por ahora, sólo comparto el "tip" en caso que alguien tenga un problema similar.

http://code.google.com/p/memefx/

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, 2 de febrero de 2009

JavaFX: Menú flotante (popup menu)


Este código utiliza un menú flotante que implemente yo. Es un trabajo en progreso, así que tiene un par de detalles pendientes... pero, por ahora, quizás le puede servir a alguien para su aplicación o para aprender como funciona...



Como he dicho, estoy aprendiendo JavaFX script, así que es probable que haga cosas de maneras inapropiadas, no se crean que soy un experto! ;) ... aun... en todo caso, implementar el menú flotante me tomó sólo un par de horas desde que comencé (de cero), para que vean lo productivo que puede ser este lenguaje.

Por cierto, se pueden crear menús flotantes sin tanta configuración, sólo son necesarias las opciones (el texto de la opción [text:] y la función a las que están asociadas [call:]), las demás configuraciones son opcionales... y ojo, que hay bastantes opciones por probar y combinar.... por cierto, JavaFX script permite hacer combinaciones como el Timeline que agregué para que cambie el color del borde del menú flotante. Quizás puedes experimentar agregándole un Interpolador de resorte para que se vea más simpático al aparecer o elegir una opción, o que el menú aparezca rotando cuando es lanzado, etc.

Aquí está el proyecto Netbeans 6.5 completo (Download the complete Netbeans project here, alpha version).

package popupmenu;

import javafx.stage.Stage;
import javafx.scene.*;
import javafx.scene.text.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.animation.*;
import javafx.scene.input.*;


var screenWidth=500.0;
var screenHeight=500.0;

// Primer menu flotante
var popupmenu=popupMenu{

corner:20
padding:8
borderWidth:4
borderColor:bind dynamicColor

// opciones del menu
content: [
menuItem { text:"Say Hello!", call: hello },
menuItem { text:"Again, say Hello!", call: again },

//menuSeparator { },
menuItem { text:"Say Bye!", call: bye }
]

};

// Timeline anima el borde del primer menu flotante
var dynamicColor:Color;
Timeline {
repeatCount:Timeline.INDEFINITE
autoReverse:true
keyFrames: [
at (0s) {dynamicColor => Color.YELLOW }
at (0.5s) {dynamicColor => Color.DARKBLUE}
at (1s) {dynamicColor => Color.LIGHTSALMON}
]
}.play();


// Segundo menu flotante
var popupCircle=popupMenu{

font: Font { size:20 };
gradient: LinearGradient { proportional: false
startX: 125.0, startY: 0.0, endX: 225.0, endY: 0.0
stops: [ Stop { offset: 0.0 color: Color.BLACK },
Stop { offset: 1.0 color: Color.RED } ] }
fill:Color.TRANSPARENT
stroke:Color.WHITE
highlight: Color.YELLOW
verticalSpacing:10

// opciones del menu
content: [
menuItem { text:"Multiline options\n"
"for your menu!", call: helloCircle },
menuItem { text:"This is a second\n"
"multiline option!", call: helloCircle },
]

};

// Tercer menu flotante
var popupmenu2=popupMenu{

font: Font { size: 18, name:"Verdana", embolden:true };
gradient: LinearGradient { proportional: true
stops: [ Stop { offset: 0.0 color: Color.GRAY },
Stop { offset: 1.0 color: Color.WHITE } ] }
fill:Color.TRANSPARENT
corner:20
padding:16
verticalSpacing:6
rotation:-25
highlight:Color.WHITE
highlightStroke:Color.RED

// opciones del menu
content: [
menuItem { text:"Say Hello!", call: hello },
menuItem { text:"Again, say Hello!", call: again },
menuItem { text:"Say Bye!", call: bye }
]

};


// funciones asignada a menus
function hello(e:MouseEvent):Void {
println("hello {e.x},{e.y}");
};

function helloCircle(e:MouseEvent):Void {
println("hello Circle {e.x},{e.y}");
};

function again(e:MouseEvent):Void {
println("hello, again {e.x},{e.y}");
};

function bye(e:MouseEvent):Void {
println("bye! {e.x},{e.y}");
};


Stage {
title: "Application title"
width: bind screenWidth with inverse
height: bind screenHeight with inverse
scene: Scene {
content: [
// agrega un fondo a la ventana
Rectangle {
fill: Color.BLUE
width: bind screenWidth
height: bind screenHeight
// le asigna un menu flotante
onMousePressed: function(e) {
popupmenu.event=e;
}
},
// crea un circulo
Circle {
// bloquea el click para que no dispare el menu flotante del fondo
blocksMouse:true
centerX: 100,
centerY: 100
radius: 40
fill: Color.RED
// le asigna un menu flotante
onMousePressed: function(e) {
popupCircle.event=e;
}
},
// crea un segundo circulo
Circle {
// bloquea el click para que no dispare el menu flotante del fondo
blocksMouse:true
centerX: 300,
centerY: 300
radius: 80
fill: Color.YELLOW
// le asigna un menu flotante
onMousePressed: function(e) {
popupmenu2.event=e;
}
},
// incluye los menus flotantes
popupmenu,
popupmenu2,
popupCircle
]
}
}

domingo, 18 de enero de 2009

JavaFX: Objetos arrastrables con "efectos"


Este ejemplo incluye 3 clases:

1) Una clase (SpringInterpolator) que define un nuevo tipo de "interpolador" que genera un movimiento "elástico" (de resorte)

2) Una clase (DraggableObj) que permite que los elementos asignados sean "arrastrables" (drag and drop).

3) La clase principal (Main) que implementa la aplicación y que agrega 4 elementos para arrastrar por la ventana.



archivo SpringInterpolator.fx

package DraggableClass;

import javafx.animation.SimpleInterpolator;
import java.lang.Math;

public class SpringInterpolator extends SimpleInterpolator {
// amplitud de la onda
// controla que tan lejos puede llegar el objeto desde su punto final
public-init var amplitude:Number = 1.0;
// determina el peso del objeto
// hace el movimiento de la onda mas grande y llega mas lejos
public-init var mass:Number = 0.058;
// rigidez del movimiento de la onda o resolte
// hace la onda mas corta o ceñida
public-init var stiffness:Number = 12.0;
// hace la onda de fase, de modo que el objeto
// no acabe en el lugar de descanso.
// esta variable generalmente no cambia
public-init var phase:Number = 0.0;

// si actua como un resorte normal o rebota
public-init var bounce:Boolean = false;

// usado para calculos internos
var pulsation:Number;

init {
this.pulsation = Math.sqrt(stiffness / mass);
}

// ecuacion del resorte
override public function curve(t: Number) : Number {
var t2 = -Math .cos(pulsation * t + phase + Math.PI) * (1 - t) * amplitude ;
// usa el valor absoluto de la distancia si rebota
if(bounce) {
return 1 - Math.abs(t2);
} else {
return 1 - t2;
}
}
}

archivo DraggableObj.fx

package DraggableClass;

import javafx.scene.Group;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.shape.*;
import javafx.scene.paint.*;
import javafx.animation.Timeline;
import javafx.animation.Timeline.*;
import javafx.animation.Interpolator;
import javafx.animation.Interpolator.*;


public class DraggableObj extends CustomNode {

public var content: Node[];

var endX = 0.0;
var endY = 0.0;
var startX = 0.0;
var startY = 0.0;

var op:Number=100;
var scale:Number=100;

// produce un parpadeo rapido al
// al soltar los objetos arrastrados
var t = Timeline {
repeatCount: 3
keyFrames: [
at (0s) { op => 100.0 },
at (0.05s) { op => 0.0 }
]
}

// instancia el interpolador de resorte
def spring = SpringInterpolator { bounce: true};

// escala objetos con efecto de resorte
var s = Timeline {
keyFrames: [
at (1.5s) { scale => 100.0 tween spring},
]
};

// escala objectos de tamano original
// a tamano 50% mas grande al hacer
// click sobre ellos
var i = Timeline {
keyFrames: [
at (0s) { scale => 100.0 },
at (0.3s) { scale => 150.0},
]
};


override function create() : Node {

// produce una variacion constante en la
// opacidad de los elementos arrastrables
Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames: [
at (0s) { op => 70.0 },
at (0.3s) { op => 100.0 tween Interpolator.EASEBOTH}
]
}.play();

Group {
translateX: bind endX
translateY: bind endY
content: bind content
opacity: bind op/100.0
scaleX: bind scale/100.0
scaleY: bind scale/100.0

onMouseDragged: function(e) {
endX = e.dragX-startX;
endY = e.dragY-startY;
}
onMousePressed: function(e) {
startX = e.dragX-endX;
startY = e.dragY-endY;
s.stop();
i.playFromStart();
}
onMouseReleased: function(e) {
t.playFromStart();
s.time=0s;
s.play();
}
};
}

}

archivo Main.fx

package DraggableClass;

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.*;
import javafx.scene.paint.*;
import javafx.scene.shape.*;
import javafx.scene.input.MouseEvent;


var newCircle=DraggableObj{
translateX:700
translateY:200
content: Circle {
radius: 100
fill: Color.RED
opacity:0.75
}
};

// este objeto incluye un ARRAY (arreglo) de figuras
var newCircle2=DraggableObj{
translateX:200
translateY:200
content: [
Circle {
opacity:0.5
fill:Color.BLUE
radius:70
},
Rectangle {
translateX:-50
translateY:-50
width:100
height:100
rotate:45
fill:Color.GREEN
opacity:0.5
}
]
};

var newImage=DraggableObj{
translateX:200
translateY:500
content: ImageView {
opacity:0.8
preserveRatio:true
fitWidth:200
image: Image {
// url: "file:/C:/Users/myuser/Pictures/2008a.png"
url: "http://www.google.com/intl/en_ALL/images/logo.gif"
}
}
}

var newRect=DraggableObj{
translateX:700
translateY:500
content: Rectangle {
width:100
height:100
rotate:45
fill:Color.PURPLE
opacity:0.5
}
};


Stage {
title: "Application title"
width: 1200
height: 750
scene: Scene {
// Incluye un ARRAY de objetos
content: [
newCircle,
newCircle2,
newImage,
newRect
]
}
}