I just started working with JavaFX and have a question. In my project i want to use a rotating rectangle. But the rectangle only rotates about its center and i want it to rotate around its upper left corner.
Like in this picture (from here):
Here some code like in my project:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.shape.Rectangle;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.*;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
Group root = new Group();
Scene scene = new Scene(root, 500, 500);
//create rectangle
Rectangle rect = new Rectangle(10, 10, 200, 15);
rect.setTranslateX(250);
rect.setTranslateY(250);
rect.setFill(Color.BLACK);
root.getChildren().add(rect);
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
stage.getScene().setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.LEFT) {
rect.setRotate(rect.getRotate()-5); //<-- rotate rectangle here
} else if (e.getCode() == KeyCode.RIGHT){
rect.setRotate(rect.getRotate()+5); //<-- rotate rectangle here
}
});
}
};
timer.start();
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In this case the rectangle rotates if the arrow keys are pressed.
You need to use Transform and Rotate specifically to rotate a node around a custom pivot.
//Create a Rotate Object
Rotate rotate = new Rotate();
rotate.setPivotX(node.getX()); //Pivot X Top-Left corner
rotate.setPivotY(node.getY()); //Pivot Y
rotate.setAngle(angle); //Angle degrees
//Add the transform to the node
node.getTransforms().add(rotate);
In your code
final Rotate rotate = new Rotate();
rect.getTransforms().add(rotate);
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
stage.getScene().setOnKeyPressed(e -> {
rotate.setPivotX(rect.getX());
rotate.setPivotY(rect.getY());
if (e.getCode() == KeyCode.LEFT) {
rotate.setAngle(rotate.getAngle() - 5);
} else if (e.getCode() == KeyCode.RIGHT){
rotate.setAngle(rotate.getAngle() + 5);
}
});
}
};
Related
I have a question that as per object concerns the Canvas and its GraphiContext.
In the following code I have reported a JavaFX Application that has the Canvas as its main object.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class canvasSVG extends Application{
private Double angle = 0.0;
#Override
public void start(Stage stage) {
Canvas canvas = new Canvas(500, 500);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFill(Color.GREEN);
gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
String svgPath = "m 0 10 v -24 M 0 -14 L 8 -16 M -2 10 h 4 l -2 5 l -2 -5";
canvas.setOnMousePressed(e->{
if(e.getButton()==MouseButton.PRIMARY) {
System.out.println("PUT: "+ angle);
gc.save();
gc.setStroke(Color.BLUE);
gc.translate(250,250);
gc.rotate(angle);
gc.scale(10, 10);
gc.appendSVGPath(svgPath);
gc.stroke();
angle = angle+50;
gc.restore();
}
});
canvas.setOnMouseClicked(e->{
if(e.getButton()==MouseButton.SECONDARY) {
System.out.println("CLEAN "+ angle);
gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
gc.setFill(Color.GREEN);
gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
});
StackPane pane = new StackPane(canvas);
Scene scene = new Scene(pane);
stage.setTitle("Canvas Demo");
stage.setScene(scene);
stage.sizeToScene();
stage.centerOnScreen();
stage.show();
}
public static void main(String[] args) {
launch(canvasSVG.class);
}
}
On clicking with the left mouse button I add the SVG path to the canvas and on clicking with the right mouse button I remove it from the canvas.
The problem is that once the rotation has happened the first time, the angle of the geometric figure in the canvas doesn't change.
The method appendSVGPath() specifies: "The coordinates are transformed by the current transform as they are added to the path and unaffected by subsequent changes to the transform." As an alternative, rotate the enclosing Canvas as shown below. Also consider this alternate approach to scaling SVGPath.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/** #see https://stackoverflow.com/a/70945900/230513 */
public class CanvasSVG extends Application {
private static final double DIM = 400;
private static final Color BG = Color.GREEN;
private final Canvas canvas = new Canvas(DIM, DIM);
private final GraphicsContext gc = canvas.getGraphicsContext2D();
private Double angle = 0.0;
#Override
public void start(Stage stage) {
clear();
draw();
canvas.setOnMousePressed(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
draw();
angle += 50;
canvas.setRotate(angle);
} else if (e.getButton() == MouseButton.SECONDARY) {
clear();
angle = 50.0;
}
});
StackPane pane = new StackPane(canvas);
pane.setBackground(new Background(new BackgroundFill(
BG, CornerRadii.EMPTY, Insets.EMPTY)));
Scene scene = new Scene(pane);
stage.setTitle("Canvas Demo");
stage.setScene(scene);
stage.centerOnScreen();
stage.show();
}
private void draw() {
String svgPath = "m 0 10 v -24 M 0 -14 L 8 -16 M -2 10 h 4 l -2 5 l -2 -5";
gc.save();
gc.setStroke(Color.BLUE);
gc.translate(DIM / 2, DIM / 2);
gc.scale(10, 10);
gc.appendSVGPath(svgPath);
gc.stroke();
gc.restore();
}
private void clear() {
gc.setFill(BG);
gc.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
public static void main(String[] args) {
launch(CanvasSVG.class);
}
}
I'm trying to create a program, which should draw a rectangle on a canvas based on two left mouse clicks and clears the canvas with one right click.
The rectangle should be created in a way, where the first mouse click simulates one corner of the rectangle, and the next mouse click simulates the diagonal corner of the rectangle compared to the first mouse click.
I'm stuck on how to store the coordinates for the first mouse click, and then put the second mouse click to good use, as the rectangle per definition is created based on only 1 set of coordinates, which is the upper-left corner of the rectangle.
Right now, all my code does is that it draws fixed sized rectangles (50x25) which obviously isn't what I want. This is just to see if the clearing part works.
This is what I've got so far:
package application;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class DrawRectangle extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Title");
Canvas canv = new Canvas(500, 400);
GraphicsContext gc = canv.getGraphicsContext2D();
EventHandler<MouseEvent> event = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY) {
double x = event.getX();
double y = event.getY();
gc.setFill(Color.BLUE);
gc.fillRect(x, y, 50, 25);
}
}
};
canv.addEventHandler(MouseEvent.MOUSE_CLICKED, event);
EventHandler<MouseEvent> event2 = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event2) {
if (event2.getButton() == MouseButton.SECONDARY) {
gc.clearRect(0, 0, 500, 400);
}
}
};
canv.addEventHandler(MouseEvent.MOUSE_CLICKED, event2);
StackPane root = new StackPane();
root.getChildren().add(canv);
primaryStage.setScene(new Scene(root, 500, 400));
primaryStage.show();
}
}
I don't know if it matters which corners of the rectangle the mouse clicks should simulate, maybe someone got any ideas?
Best regards and happy new year
Just save the first click point in a member variable, then use it and reset it when the user makes a second click point.
Note: the sample code below uses a switch expression from Java 13+. If switch expressions are not available in your Java version, convert it to a standard switch statement or if/else clauses.
import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class DrawRectangle extends Application {
private static final int W = 500;
private static final int H = 400;
private Point2D savedPoint = null;
#Override
public void start(Stage stage) {
Canvas canvas = new Canvas(W, H);
GraphicsContext gc = canvas.getGraphicsContext2D();
canvas.setOnMouseClicked(event -> {
switch (event.getButton()) {
case PRIMARY -> handlePrimaryClick(gc, event);
case SECONDARY -> gc.clearRect(0, 0, W, H);
}
});
stage.setResizable(false);
stage.setScene(new Scene(new StackPane(canvas), W, H));
stage.show();
}
private void handlePrimaryClick(GraphicsContext gc, MouseEvent event) {
Point2D clickPoint = new Point2D(event.getX(), event.getY());
if (savedPoint == null) {
savedPoint = clickPoint;
} else {
Rectangle2D rectangle2D = getRect(savedPoint, clickPoint);
gc.setFill(Color.BLUE);
gc.fillRect(
rectangle2D.getMinX(),
rectangle2D.getMinY(),
rectangle2D.getWidth(),
rectangle2D.getHeight()
);
savedPoint = null;
}
}
private Rectangle2D getRect(Point2D p1, Point2D p2) {
return new Rectangle2D(
Math.min(p1.getX(), p2.getX()),
Math.min(p1.getY(), p2.getY()),
Math.abs(p1.getX() - p2.getX()),
Math.abs(p1.getY() - p2.getY())
);
}
public static void main(String[] args) {
launch(args);
}
}
I am working on a javafx program to create three buttons which are "circle", "ellipse" and "reverse". The circle button is the first thing shown when the program is run, the reverse button is supposed to correspond with the movement of the rectangle around the circle. I am having trouble getting the reverse button to work, I set autoReverse to true but it isn't doing anything. My second issue with the code is when the ellipse button is clicked the class MyEllipse isn't showing the ellipse shape like it is supposed to and it's not removing the circle animation from the pane. I tried to create a new pane in the EventHandler for the buttonellipse but I am assuming that isn't the correct way to do it. Any help on these two issues would be greatly appreciated.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.animation.PathTransition;
import javafx.scene.paint.Color;
import javafx.animation.Timeline;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Ellipse;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
import javafx.scene.layout.HBox;
import javafx.event.EventHandler;
import javafx.stage.Stage;
public class exam3b extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rectangle = new Rectangle (0, 0, 25, 50);
rectangle.setFill(Color.ORANGE);
Circle circle = new Circle(115, 90, 45);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
PathTransition pt = new PathTransition();
pt.setDuration(Duration.millis(4000));
pt.setPath(circle);
pt.setNode(rectangle);
pt.setOrientation(
PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pt.setCycleCount(Timeline.INDEFINITE);
pt.setAutoReverse(false);
pt.play();
circle.setOnMousePressed(e -> pt.pause());
circle.setOnMouseReleased(e -> pt.play());
HBox panel = new HBox(10);
panel.setAlignment(Pos.BOTTOM_CENTER);
Button button = new Button("Circle");
Button buttonellipse = new Button("Ellipse");
Button reverse = new Button("Reverse");
panel.getChildren().addAll(button,buttonellipse,reverse);
button.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
reverse.setVisible(true);
}
});
reverse.setOnAction(new EventHandler<ActionEvent>() //supposed to make rectangle move in reverse direction
{
#Override
public void handle(ActionEvent e)
{
pt.setAutoReverse(true);
}
});
buttonellipse.setOnAction(new EventHandler<ActionEvent>() //button to make ellipse appear from class MyEllipse, reverse button is supposed to disappear
{
#Override
public void handle(ActionEvent e)
{
reverse.setVisible(false);
Pane ellipse = new Pane();
ellipse.getChildren().add(new MyEllipse());
}
});
Pane pane = new Pane();
pane.getChildren().addAll(panel,circle,rectangle);
Scene scene = new Scene(pane, 350, 250);
primaryStage.setTitle("exam3b");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class MyEllipse extends Pane
{
private void paint() {
getChildren().clear();
for (int i = 0; i < 16; i++) {
Ellipse e1 = new Ellipse(getWidth() / 2, getHeight() / 2,
getWidth() / 2 - 50, getHeight() / 2 - 50);
e1.setStroke(Color.color(Math.random(), Math.random(),
Math.random()));
e1.setFill(Color.WHITE);
e1.setRotate(i * 180 / 16);
getChildren().add(e1);
}
}
#Override
public void setWidth(double width) {
super.setWidth(width);
paint();
}
#Override
public void setHeight(double height) {
super.setHeight(height);
paint();
}
}
You had an issue with how you were using MyEllipse, in that you were never adding it to your root pane nor were you settign the width/height (which leads to your paint method being called). I renamed your root pane to 'root'. Created an instance of 'MyEllipse', and in the 'Ellipse' button i add the instance of 'MyEllipse' to the root pane.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.animation.PathTransition;
import javafx.scene.paint.Color;
import javafx.animation.Timeline;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Ellipse;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
import javafx.scene.layout.HBox;
import javafx.event.EventHandler;
import javafx.stage.Stage;
public class exam3b extends Application {
#Override
public void start(Stage primaryStage) {
Rectangle rectangle = new Rectangle(0, 0, 25, 50);
rectangle.setFill(Color.ORANGE);
Circle circle = new Circle(115, 90, 45);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
PathTransition pt = new PathTransition();
pt.setDuration(Duration.millis(4000));
pt.setPath(circle);
pt.setNode(rectangle);
pt.setOrientation(
PathTransition.OrientationType.ORTHOGONAL_TO_TANGENT);
pt.setCycleCount(Timeline.INDEFINITE);
pt.setAutoReverse(true);
pt.play();
circle.setOnMousePressed(e -> pt.pause());
circle.setOnMouseReleased(e -> pt.play());
HBox panel = new HBox(10);
panel.setAlignment(Pos.BOTTOM_CENTER);
Button button = new Button("Circle");
Button buttonellipse = new Button("Ellipse");
Button reverse = new Button("Reverse");
panel.getChildren().addAll(button, buttonellipse, reverse);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
reverse.setVisible(true);
}
});
reverse.setOnAction(new EventHandler<ActionEvent>() //supposed to make rectangle move in reverse direction
{
#Override
public void handle(ActionEvent e) {
pt.setAutoReverse(true);
}
});
Pane root = new Pane();
MyEllipse myEllipse = new MyEllipse();
myEllipse.setWidth(200);
myEllipse.setHeight(400);
buttonellipse.setOnAction(new EventHandler<ActionEvent>() //button to make ellipse appear from class MyEllipse, reverse button is supposed to disappear
{
#Override
public void handle(ActionEvent e) {
// reverse.setVisible(false);
if (root.getChildren().contains(myEllipse)) {
root.getChildren().remove(myEllipse);
} else {
System.out.println("adding ellipse");
root.getChildren().add(myEllipse);
}
}
});
root.getChildren().addAll(panel, circle, rectangle);
Scene scene = new Scene(root, 350, 250);
primaryStage.setTitle("exam3b");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class MyEllipse extends Pane {
public MyEllipse() {
}
private void paint() {
getChildren().clear();
for (int i = 0; i < 16; i++) {
Ellipse e1 = new Ellipse(getWidth() / 2, getHeight() / 2,
getWidth() / 2 - 50, getHeight() / 2 - 50);
e1.setStroke(Color.color(Math.random(), Math.random(),
Math.random()));
e1.setFill(Color.WHITE);
e1.setStrokeWidth(1);
e1.setRotate(i * 180 / 16);
getChildren().add(e1);
}
}
#Override
public void setWidth(double width) {
super.setWidth(width);
paint();
}
#Override
public void setHeight(double height) {
super.setHeight(height);
paint();
}
}
I am making a javafx application that creates a bounded rectangle around the circles the user creates when primary mouse clicking. The user can also remove a circle with the secondary mouse button and the bounding rectangle should react accordingly and use the remaining circles as its upper and lower limits. The problem with my program is that it does not work when I try to remove more than one circle in a row (it only removes and resizes for the last circle)
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.Collections;
public class BoundRectangle extends Application {
double minX, maxX, minY, maxY;
Pane pane = new Pane();
Rectangle rectangle;
ArrayList<Circle> allCircles = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
VBox mainBox = new VBox();
Pane mainPane = new Pane(mainBox);
mainPane.setPadding(new Insets(10, 10, 10, 10));
pane.getChildren().addAll(mainPane);
mainBox.setLayoutX(10);
mainBox.setLayoutY(10);
pane.setOnMouseClicked(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
Circle circle = new Circle(e.getX(), e.getY(), 10);
allCircles.add(circle);
pane.getChildren().add(drawRectangle());
pane.getChildren().add(circle);
System.out.println("maxX " + maxX);
System.out.println("maxY " + maxY);
System.out.println("minX " + minX);
System.out.println("minY " + minY);
circle.setOnMouseClicked(evt -> {
if (evt.getButton() == MouseButton.SECONDARY) {
pane.getChildren().remove(circle);
allCircles.remove(circle);
pane.getChildren().add(drawRectangle());
}
});
circle.setStroke(Color.BURLYWOOD);
circle.setStrokeWidth(3);
circle.setFill(Color.TRANSPARENT);
}
});
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.setTitle("click circles, make rectangle");
primaryStage.show();
}
public Rectangle drawRectangle() {
refresh();
getMinMax();
if (pane.getChildren().size() == 1)
{
Rectangle rect0 = new Rectangle(0, 0, 0, 0);
return rect0;
}
Rectangle boundingRect = new Rectangle();
boundingRect.setX(minX - 10 - 2);
boundingRect.setY(minY - 10 - 2);
boundingRect.setWidth(maxX - minX + 2.0 * 10 + 2);
boundingRect.setHeight(maxY - minY + 2.0 * 10 + 2);
boundingRect.setStroke(Color.BLACK);
boundingRect.setStrokeWidth(2);
boundingRect.setFill(Color.TRANSPARENT);
return boundingRect;
}
public void getMinMax() {
maxY = allCircles.get(0).getCenterY();
minY = allCircles.get(0).getCenterY();
maxX = allCircles.get(0).getCenterX();
minX = allCircles.get(0).getCenterX();
for (Circle c : allCircles) {
if (c.getCenterX() < minX)
minX = c.getCenterX();
if (c.getCenterX() > maxX)
maxX = c.getCenterX();
if (c.getCenterY() < minY)
minY = c.getCenterY();
if (c.getCenterY() > maxY)
maxY = c.getCenterY();
}
}
private void refresh() {
ObservableList<Node> list = pane.getChildren();
for (Node c : list) {
if (c instanceof Rectangle) {
pane.getChildren().remove(c);
break;
}
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
The last circle you add appears on top of the rectangle; however the rectangle appears on top of all the other circles. So only the last circle added will get the mouse clicks (clicks on other circles are targeted to the rectangle).
The quickest fix is to make the rectangle mouse transparent:
boundingRect.setMouseTransparent(true);
A better solution overall might be just to create one rectangle and update its x, y, width and height properties. That way you can just ensure the rectangle is added once and remains at the bottom of the stack.
I have a program where 2 circles are dragged in a pane. There is also a line connecting them and the distance displayed above it. My problem lies when I drag the circles at a slow pace with the mouse they move fine, but when I move it more quickly the circles stop.
here is where the circle drag is calculated
pane.setOnMouseDragged(e -> {
if (circle1.contains(e.getX(), e.getY())) {
pane.getChildren().clear();
circle1.setCenterX(e.getX());
circle1.setCenterY(e.getY());
pane.getChildren().addAll(getLine(circle1, circle2), circle1,
circle2, getText(circle1, circle2));
}
else if (circle2.contains(e.getX(), e.getY())) {
pane.getChildren().clear();
circle2.setCenterX(e.getX());
circle2.setCenterY(e.getY());
pane.getChildren().addAll(getLine(circle1, circle2), circle1,
circle2, getText(circle1, circle2));
}
});
I think what is happening is that when the mouse moves quickly, the distance moved between processing two consecutive events takes it outside the bounds of the circle, so the if condition becomes false. You probably need to register the mouse handlers on the circles themselves, instead of the pane. (As an aside, why clear and rebuild the pane, instead of just update the line?)
Here's an example using these techniques:
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class DraggingCircles extends Application {
#Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
Circle circle1 = createDraggingCircle(50, 50, 25, Color.BLUE);
Circle circle2 = createDraggingCircle(350, 350, 25, Color.RED);
Line line = new Line();
line.startXProperty().bind(circle1.centerXProperty());
line.startYProperty().bind(circle1.centerYProperty());
line.endXProperty().bind(circle2.centerXProperty());
line.endYProperty().bind(circle2.centerYProperty());
pane.getChildren().addAll(circle1, circle2, line);
Scene scene = new Scene(pane, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private Circle createDraggingCircle(double x, double y, double radius, Color fill) {
Circle circle = new Circle(x, y, radius, fill);
ObjectProperty<Point2D> mouseLocation = new SimpleObjectProperty<>();
circle.setOnMousePressed(e -> {
mouseLocation.set(new Point2D(e.getX(), e.getY()));
});
circle.setOnMouseDragged(e -> {
double deltaX = e.getX() - mouseLocation.get().getX();
double deltaY = e.getY() - mouseLocation.get().getY();
circle.setCenterX(circle.getCenterX() + deltaX);
circle.setCenterY(circle.getCenterY() + deltaY);
mouseLocation.set(new Point2D(e.getX(), e.getY()));
});
return circle ;
}
public static void main(String[] args) {
launch(args);
}
}