Reputation: 2192
How can I group shapes (e.g. circles) in JavaFX for dragging them around? The example code is based on the Oracle tutorial. Each single circle can be moved. I want to move the blue circle alone when dragging it. I want to move the green and the blue circle when clicking and dragging the green one and all three of them when clicking and dragging the red one. Any ideas?
public class DragGroupSample extends Application {
public static void main( String[] args ) {
launch();
}
private void makeDraggable( Circle circle ) {
DragContext dragContext = new DragContext();
// --- remember initial coordinates of mouse cursor and node
circle.addEventFilter( MouseEvent.MOUSE_PRESSED, (
final MouseEvent mouseEvent ) -> {
dragContext.dx = mouseEvent.getX() - circle.getCenterX();
dragContext.dy = mouseEvent.getY() - circle.getCenterY();
} );
// --- Shift node calculated from mouse cursor movement
circle.addEventFilter( MouseEvent.MOUSE_DRAGGED, (
final MouseEvent mouseEvent ) -> {
circle.setCenterX( mouseEvent.getX() + dragContext.dx );
circle.setCenterY( mouseEvent.getY() + dragContext.dy );
} );
// --- Drop card onto allowed target field
circle.addEventFilter( MouseEvent.MOUSE_RELEASED, (
final MouseEvent mouseEvent ) -> {
circle.setCenterX( mouseEvent.getX() + dragContext.dx );
circle.setCenterY( mouseEvent.getY() + dragContext.dy );
} );
}
@Override
public void start( Stage primaryStage ) throws Exception {
Circle[] circles = new Circle[3];
circles[0] = new Circle( 30.0, 30.0, 30.0, Color.RED );
circles[1] = new Circle( 45.0, 45.0, 30.0, Color.GREEN );
circles[2] = new Circle( 60.0, 60.0, 30.0, Color.BLUE );
for ( Circle circle : circles ) {
makeDraggable( circle );
}
Group root = new Group();
root.getChildren().addAll( circles[0], circles[1], circles[2] );
primaryStage.setResizable( false );
primaryStage.setScene( new Scene( root, 400, 350 ) );
primaryStage.setTitle( DragGroupSample.class.getSimpleName() );
primaryStage.show();
}
private static final class DragContext {
public double dx, dy;
}
}
Upvotes: 0
Views: 3930
Reputation: 209358
Just move all the circles you want to move. It's probably easier to store the last mouse location relative to something fixed (like the scene), instead of working relative to the circle.
Here's one way, there are many:
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class DragGroupSample extends Application {
public static void main( String[] args ) {
launch();
}
// list of nodes that are dragged. Can be modified at any time (on the FX Application Thread):
private final List<Circle> nodesToDrag = new ArrayList<>();
private final Circle[] circles = new Circle[3] ;
private void makeDraggable( Circle circle ) {
MouseLocation lastMouseLocation = new MouseLocation();
// --- remember initial coordinates of mouse cursor and node
circle.addEventFilter( MouseEvent.MOUSE_PRESSED, (
final MouseEvent mouseEvent ) -> {
lastMouseLocation.x = mouseEvent.getSceneX() ;
lastMouseLocation.y = mouseEvent.getSceneY() ;
// just some example logic to modify the list of dragged nodes:
boolean found = false ;
for (Circle c : circles) {
if (c == circle) found = true ;
if (found) nodesToDrag.add(c);
}
} );
// --- Shift node calculated from mouse cursor movement
circle.addEventFilter( MouseEvent.MOUSE_DRAGGED, (
final MouseEvent mouseEvent ) -> {
double deltaX = mouseEvent.getSceneX() - lastMouseLocation.x ;
double deltaY = mouseEvent.getSceneY() - lastMouseLocation.y ;
for (Circle c : nodesToDrag) {
c.setCenterX( c.getCenterX() + deltaX );
c.setCenterY( c.getCenterY() + deltaY );
}
lastMouseLocation.x = mouseEvent.getSceneX();
lastMouseLocation.y = mouseEvent.getSceneY();
} );
circle.addEventFilter(MouseEvent.MOUSE_RELEASED, mouseEvent -> nodesToDrag.clear());
}
@Override
public void start( Stage primaryStage ) throws Exception {
circles[0] = new Circle( 30.0, 30.0, 30.0, Color.RED );
circles[1] = new Circle( 45.0, 45.0, 30.0, Color.GREEN );
circles[2] = new Circle( 60.0, 60.0, 30.0, Color.BLUE );
for ( Circle circle : circles ) {
makeDraggable( circle );
}
Group root = new Group();
root.getChildren().addAll( circles[0], circles[1], circles[2] );
primaryStage.setResizable( false );
primaryStage.setScene( new Scene( root, 400, 350 ) );
primaryStage.setTitle( DragGroupSample.class.getSimpleName() );
primaryStage.show();
}
private static final class MouseLocation {
public double x, y;
}
}
Upvotes: 1