August 11th, 2008JavaFX, Draggable Nodes
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();













August 13th, 2008 at 4:14 am
Excellent work….I m impressed with your Picture Dragging Example and Ball Shade…example….
August 14th, 2008 at 10:39 am
Hi Sir , Thanks for your nice job ,Well done . I need one help from you . I need same as you did on picture draggable but I wanted when i click on one picture that picture come up “I mean come first top” . and i don`t want they join together and move . I wanted single chose and other back don`t move . Please help me . on that matter . I need to work with that on some panel or some canvas .
thank you again .
Looking for your reply as soon as possible
with best regard
Ali
August 14th, 2008 at 11:26 am
Ali jamali, one way to change the order the nodes appears in the scene is changing the order they are in the ‘content’ field of the Stage object.
As a list, you can change it.
Maybe looking at the JavaFX DOC at http://openjfx.java.sun.com/current-build/doc/ to see if there’s a easier way.
August 16th, 2008 at 5:03 pm
Dear Silveria ,
I have set one onMouseClick for my canvas , But I can not make force action happen in first focus canvas. In other world I have 6 canvas . When I want when i click on one page it become my focus page and come first page . but if other canvas be back of that and Mouse x & y be in the same position must select the topper one . But i don`t know how can i do that . I see the Document but it`s too much complicated to understand with out code example . can you suggest me something .
August 19th, 2008 at 4:37 pm
Hello Silveira
could you tel me how to bind an inserted class property with the new javafx?
i have a code in old javafx :
class A extends CompositeNode
{
attribute x;
}
and i want to add new other classes to it and bind with the attribute..
content:
[
A{
var:me <= the way to accessing the attribute
content:
B{foo:bind me.x}
}
]
August 19th, 2008 at 10:27 pm
I think your code san be more simple right ?
onMousePressed: function(e:MouseEvent):Void {
startX = endX;
startY = endY;
}
onMouseDragged: function(e:MouseEvent):Void {
endX = e.getDragX()+startX;
endY = e.getDragY()+startY;
}
Regards..
August 25th, 2008 at 4:26 pm
wildan, yes! Worked here.
Thanks for this advice.
September 29th, 2008 at 2:17 pm
Wildan, no, I noticed now that this doesn’t work properly in the second click.
The correct is the code from the example in the post.
October 4th, 2008 at 4:24 pm
[...] 14 to 42 is the same dragging approach I showed in the post Draggable Nodes, but this time creating a class that inherits the behavior [...]
October 30th, 2008 at 12:26 pm
[...] on JavaFX. First I created a movable rectangle using the same idea of draggable nodes I already had posted before. import javafx.input.MouseEvent; import javafx.scene.geometry.Rectangle; public class [...]
November 15th, 2008 at 11:19 am
Hi,
I’ve used your rotating images script to test a container. You can check the result at : http://crowtheries.net/?p=83