One thing that I like a lot to do with JavaFX is draggable objects. Due to some recent changes in the JavaFX syntax my old codes for that are no longer working. Joshua Marinacci from Sun’s JavaFX engineering team and other guys from the JavaFX community gave me some tips. Here some strategies I’m using for making draggable nodes in JavaFX.
In this first example, a simple draggable ellipse.
video url: http://www.youtube.com/watch?v=pAJHH-mPLaQ
import javafx.application.*;
import javafx.scene.paint.*;
import javafx.scene.geometry.*;
import javafx.input.*;
Frame {
width: 300, height: 300, visible: true
stage: Stage {
content: [
Ellipse {
var endX = 0.0; var endY = 0.0
var startX = 0.0; var startY = 0.0
centerX: 150, centerY: 150
radiusX: 80, radiusY: 40
fill: Color.ORANGE
translateX: bind endX
translateY: bind endY
onMousePressed: function(e:MouseEvent):Void {
startX = e.getDragX()-endX;
startY = e.getDragY()-endY;
}
onMouseDragged: function(e:MouseEvent):Void {
endX = e.getDragX()-startX;
endY = e.getDragY()-startY;
}
}
]
}
}
When you need to create a group of draggable objects, you can try thie approach of a draggable group like this. Inside on it, you can put whatever you want.
Video url: http://www.youtube.com/watch?v=mHOcPRrgQCQ
import javafx.application.*;
import javafx.scene.paint.*;
import javafx.scene.geometry.*;
import javafx.input.*;
import javafx.scene.*;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.animation.*;
// a graggable group
public class DragGroup extends CustomNode{
public attribute content: Node[];
private attribute endX = 0.0;
private attribute endY = 0.0;
private attribute startX = 0.0;
private attribute startY = 0.0;
public function create(): Node {
return Group{
translateX: bind endX
translateY: bind endY
content: bind content
}
}
override attribute onMousePressed = function(e:MouseEvent):Void {
startX = e.getDragX()-endX;
startY = e.getDragY()-endY;
}
override attribute onMouseDragged = function(e:MouseEvent):Void {
endX = e.getDragX()-startX;
endY = e.getDragY()-startY;
}
}
// angle animation, cycles between 0 to 360 in 36 seconds
var angle = 0.0;
var angleAnimation = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time: 0s
values:
angle => 0.0
},
KeyFrame{
time: 36s
values :
angle => 360.0 tween Interpolator.LINEAR
}
]
}
// some pictures from my Flickr albums
var me = "http://farm4.static.flickr.com/3042/2746737338_aa3041f283_m.jpg";
var dog = "http://farm4.static.flickr.com/3184/2717290793_ec14c26a85_m.jpg";
var plant = "http://farm4.static.flickr.com/3014/2731177705_bed6d6b8fa_m.jpg";
var bird = "http://farm4.static.flickr.com/3190/2734919599_a0110e7ce0_m.jpg";
var me_89 = "http://farm3.static.flickr.com/2138/2308085138_7b296cc5d0_m.jpg";
Frame {
width: 640, height: 480, visible: true
stage: Stage {
fill: Color.BLACK
content: [
DragGroup{
content: ImageView {
anchorX: 120, anchorY: 90
rotate: bind 30 + angle
image: Image { backgroundLoading: true, url: me }
}
},
DragGroup {
translateX: 300, translateY: 50
content: ImageView {
anchorX: 120, anchorY: 90
rotate: bind -30 + angle
image: Image { backgroundLoading: true, url: dog }
}
},
DragGroup {
translateX: 300, translateY: 300
content: ImageView {
anchorX: 120, anchorY: 90
rotate: bind 90 + angle
image: Image { backgroundLoading: true, url: plant }
}
},
DragGroup {
translateX: 200
translateY: 200
content: ImageView {
anchorX: 120, anchorY: 90
rotate: bind 90 + angle
image: Image { backgroundLoading: true, url: bird }
}
},
DragGroup {
translateX: 30
translateY: 200
content: ImageView {
anchorX: 85, anchorY: 120
rotate: bind angle + 180
image: Image { backgroundLoading: true, url: me_89 }
}
},
]
}
closeAction: function() {
java.lang.System.exit( 0 );
}
}
angleAnimation.start();
One more example, using the same class DragGroup, we can put multiple nodes using lists.
Video url: http://www.youtube.com/watch?v=gJqy7EdtEqs
import javafx.application.*;
import javafx.scene.*;
import javafx.scene.geometry.*;
import javafx.scene.paint.*;
import javafx.input.*;
import javafx.animation.*;
import java.lang.Math;
// Class to create a draggable group of objects
public class DragGroup extends CustomNode{
public attribute content: Node[];
private attribute endX = 0.0;
private attribute endY = 0.0;
private attribute startX = 0.0;
private attribute startY = 0.0;
override attribute onMousePressed = function(e:MouseEvent):Void {
startX = e.getDragX()-endX;
startY = e.getDragY()-endY;
}
override attribute onMouseDragged = function(e:MouseEvent):Void {
endX = e.getDragX()-startX;
endY = e.getDragY()-startY;
}
public function create(): Node {
return Group{
translateX: bind endX
translateY: bind endY
content: bind content
}
}
}
// angle animation, cycles between 0 to 360 in 10 seconds
var angle = 0.0;
var angleAnimation = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time: 0s
values: angle => 0.0
},
KeyFrame{
time: 10s
values : angle => 360.0 tween Interpolator.LINEAR
}
]
}
// breath animation, go and back from 0.0 to 10.0 in 2 seconds
var breath = 0.0;
var breathAnimation = Timeline {
repeatCount: Timeline.INDEFINITE
autoReverse: true
keyFrames : [
KeyFrame {
time: 0s
values: breath => 0.0
},
KeyFrame{
time: 1s
values : breath => 10.0 tween Interpolator.LINEAR
}
]
}
// Creates n multi colored floating circles around a bigger circle
var n = 12;
var colors = [
Color.BLUE, Color.AQUA, Color.MAGENTA, Color.RED,
Color.YELLOW, Color.ORANGE, Color.HOTPINK, Color.LIME
];
var chosen = Color.YELLOW;
var floatingCircles = Group{
rotate: bind angle
content: for (i in [1..n])
Circle {
fill: colors[i mod sizeof colors]
radius: 10
centerX: Math.cos(i * 2 * Math.PI/n) * 70
centerY: Math.sin(i * 2 * Math.PI/n) * 70
onMouseClicked: function( e: MouseEvent ):Void {
chosen = colors[i mod sizeof colors];
}
}
}
var circle = Circle{
radius: bind 50 + breath
fill: bind chosen
}
Frame {
width: 400, height: 400, visible: true
stage: Stage {
fill: Color.BLACK
content: [
DragGroup{
translateX: 200, translateY: 200
content: [circle, floatingCircles]
}
]
}
closeAction: function() {
java.lang.System.exit( 0 );
}
}
// starts all animations
angleAnimation.start();
breathAnimation.start();