Reputation: 1436
I am working on an app which needs to move nodes around on a pane.
I've just recently started learning javaFx 8 so I have bare understanding of the workflow, but while I managed to get a working draggable node code working, it uses node.setTranslateX() and .setTranslateY().
This is all fine, until I tried to make the node snap to a grid that divides the scene area in both 10 height and width subdivisions.
Whenever I try to use modulos to get some sort of snapping going on, I'm stuck with the fact that I'm calling Translation transformation. I'd like to directly set the coordinates of the node myself. I've tried node.relocate(x,y) to no avail. As for node.setX() or node.setY(). These do no seem to do much.
So basically, I have two questions:
My current code uses these methods to drag the node around:
public class Boat extends ImageView {
private int size ;
private String name ;
private Double dragDeltaX, dragDeltaY;
//Constructor etc here//
this.setOnMousePressed(event -> {
this.setCursor(Cursor.CLOSED_HAND);
dragDeltaX = this.getLayoutX() + event.getX();
dragDeltaY = this.getLayoutY() + event.getY();
});
this.setOnMouseReleased(event -> {
this.setCursor(Cursor.OPEN_HAND);
this.relocate(event.getSceneX(), event.getSceneY());
});
this.setOnMouseDragged(event -> {
this.setTranslateX(event.getSceneX() - dragDeltaX);
this.setTranslateY(event.getSceneY() - dragDeltaY);
});
this.setOnMouseEntered(event -> {
this.setCursor(Cursor.OPEN_HAND);
});
}
Thanks in advance for the help,
Upvotes: 1
Views: 13355
Reputation: 209319
In most Pane
subclasses, if a Node
is managed
, then the parent pane of the node will manage its layoutX
and layoutY
properties. So setting layoutX
and layoutY
for these nodes will have no visible effect on the position of the node.
Transformations (including the translation defined by translateX
and translateY
) are applied to nodes after the layout calculations (whether the node is managed by its parent or not).
So one way to manage dragging is just to manipulate the translateX
and translateY
properties. Another way is to manipulate the layoutX
and layoutY
properties (by setting them directly or by calling relocate
), and make sure the node is not managed by its parent. I would not recommend mixing the two techniques, as your code will be harder to follow.
You can make the node unmanaged setManaged(false)
on the node, or by putting it in a Pane
instead of one of the subclasses (Pane
does not manage layout of its child nodes).
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ImageViewDragExample extends Application {
@Override
public void start(Stage primaryStage) {
Image image = createImage();
DraggableImageView imageView = new DraggableImageView(image);
// if the node is placed in a parent that manages its child nodes,
// you must call setManaged(false);
// imageView.setManaged(false);
// StackPane root = new StackPane(imageView);
// or use a plain `Pane`, which does not manage its child nodes:
Pane root = new Pane(imageView);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private Image createImage() {
WritableImage image = new WritableImage(50, 50);
for (int y = 0 ; y < 50; y++) {
for (int x = 0 ; x < 50 ; x++) {
Color c ;
if ((x > 20 && x < 30) || (y > 20 && y < 30)) {
c = Color.AZURE ;
} else {
c = Color.CORNFLOWERBLUE ;
}
image.getPixelWriter().setColor(x, y, c);
}
}
return image ;
}
public static class DraggableImageView extends ImageView {
private double mouseX ;
private double mouseY ;
public DraggableImageView(Image image) {
super(image);
setOnMousePressed(event -> {
mouseX = event.getSceneX() ;
mouseY = event.getSceneY() ;
});
setOnMouseDragged(event -> {
double deltaX = event.getSceneX() - mouseX ;
double deltaY = event.getSceneY() - mouseY ;
relocate(getLayoutX() + deltaX, getLayoutY() + deltaY);
mouseX = event.getSceneX() ;
mouseY = event.getSceneY() ;
});
}
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 5