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
]
}
}

6 comentarios:

Unknown dijo...

loque quiero saber si con javaFX se puede hacer menus mas al estilo de jquery para navegadores...¿?

Mauro dijo...

Hola... la verdad, no conozco Jquery. Acabo de mirar el sitio, pero (a primera vista) parece que no tienen demos para verlo en acción, así que no me atrevo a opinar. En todo caso, con lo poco que conozco de JavaFX, las capacidades y potencial que le veo... y sabiendo que en unos 3 o 4 meses se liberará la version 2.0, creo que pronto veremos muchos componentes muy poderosos y configurables (por cierto, JavaFX permite el uso de CSS para configurar los componentes). Tienes que considerar que esta es la primera versión de JavaFX, y que tiene menos de 2 meses de liberada... así que creo que hay que esperar un poco para tener un ambiente realmente poderoso. Por cierto, Sun tiene anunciada la liberación de un ambiente de desarrollo gráfico (de código abierto) para el desarrollo de aplicaciones JavaFX, así que eso ayudará aun más... (por ahora todo es código, a la antigua :D ... que por cierto, muchos programadores "hardcore" prefieren).

Unknown dijo...

hee lo de sun, seria bueno un ambiente gráfico sinceramente...
y que tambiém salga una version para Linux..... aunque sé q se podria emular con el archivo de mac...pero no me gusta complicarme...jeje
tenes gmail??

Alakat dijo...

Lo primero, genial. Mi enorabuena.
Tengo una duda para ti, estoy empezando a hacer jueguecitos con JavaFX y necesito hacer una pantalla de inicio (donde selecccionas del menú y luego la pantalla de juego) por ser un juego por turnos no he metido animaciones.
Ahora, no se como pintar las dos ventanas, no se si hacer los componentes a mano dos rectangulos que se superpongan o si sería posible hacer algo "más elegante" tal vez definir varios "Scene" y activar uno u otro, muchas gracias.

Otra preguntilla, sabes de algún buen foro de ayuda.
Gracias y sigue así

Mauro dijo...

Alakat, primero que todo... gracias ;)

Respecto a lo que preguntas... mmm... se me ocurre un par de soluciones:

1) Puedes poner varias Scene en un mismo Stage. Puedes crear una secuencia y pones tus Scene en ella, luego solo activas la Scene haciendo referencia con el puntero...

var escena1=Scene {...
var escena2=Scene {...

var escenaActiva=1;

var misEscenas=[escena1, escena2];

...

Stage { ...
Scene: bind escena[escenaActiva]

...

Ya había probado usar varios Scene en este artículo... http://aprendiendo-javafx.blogspot.com/2009/01/clases-de-clases.html


Una segunda alternativa (que es bastante buena), es que hagas la gráfica de tu juego con Adobe Illustrator, y separes las "pantallas" o niveles de juego, en distintas CAPAZ o LAYERS... y luego las haces visibles y las ocultas a tu antojo.

Eso lo use en el juego de Aterrizaje Lunar ... http://aprendiendo-javafx.blogspot.com/2009/01/mi-primer-juego-en-javafx-alunizaje.html

Respecto a un grupo, yo estoy suscrito en el grupo javafxprogramming@googlegroups.com

Creo que tienes que enviar un mensaje vacio con un SUBSCRIBE en el encabezado para recibir la "conversación", eso si, ponle un filtro en tu correo para que tire todo en una carpeta o algo, porque llegan bastante mensajes.

También puedes visitar esta dirección http://groups.google.com/group/javafxprogramming?hl=en?hl=en

Saludos ;)

Mauro dijo...

ups! error... debió decir...

Stage { ...
Scene: bind misEscenas[escenaActiva]
...