Joining points with javaFX - java

I wrote the following code for adding and deleting points or circles with mouse events. The next step is joining them with a line while I'm creating them (creating a polygon). I'm completely stuck and do not know where to start. I am looking for documentation but I will appreciate if somebody could point me in the right direction.
package application;
//import all needed classes
import javafx.collections.ObservableList;
import javafx.scene.input.MouseButton;
import javafx.application.Application;
import javafx.scene.shape.Circle;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.Node;
public class Main extends Application {
// using the base class of layout panes
Pane pane = new Pane();
#Override
public void start(Stage primaryStage) {
// what to do when the mouse is clicked
pane.setOnMouseClicked(e -> {
double drawX = e.getX();// position of mouse in X axle
double drawY = e.getY();// position of mouse in y axle
if (e.getButton() == MouseButton.PRIMARY) {// get the position of the mouse point when user left click
Circle circle = makeCircle(drawX, drawY);// using the makeCircle method to draw the circle where the mouse is at the click
pane.getChildren().add(circle);
} else if (e.getButton() == MouseButton.SECONDARY) {
deleteCircle(drawX, drawY);// using the deleteCircle function to delete the circle if right click on the circle
}
});
// container to show all context in a 500px by 500px windows
try {
Scene scene = new Scene(pane, 500, 500);// size of the scene
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
// method to draw the circle when left click
private Circle makeCircle(double drawX, double drawY) {
Circle circle = new Circle(drawX, drawY, 7, Color.CORAL);// create the circle and its properties(color: coral to see it better)
circle.setStroke(Color.BLACK);// create the stroke so the circle is more visible
return circle;
}
// method to delete the circle using the ObservableList class
private void deleteCircle(double deletX, double deleteY) {
// loop to create my list of circles 'til this moment
ObservableList<Node> list = pane.getChildren();
for (int i = list.size() - 1; i >= 0; i--) {
Node circle = list.get(i);
// checking which circle I want to delete
if (circle instanceof Circle && circle.contains(deletX, deleteY)) {
pane.getChildren().remove(circle);
break;
}
}
}
public static void main(String[] args) {
Application.launch(args);
}
}

I would add a change listener to the children of your pane, add a polygon to the pane and if there are more then 2 Circles, you redraw the polygon:
public class Main extends Application {
// using the base class of layout panes
Pane pane = new Pane();
Polygon polygon = new Polygon();
#Override
public void start(Stage primaryStage) {
// what to do when the mouse is clicked
pane.setOnMouseClicked(e -> {
double drawX = e.getX();// position of mouse in X axle
double drawY = e.getY();// position of mouse in y axle
if (e.getButton() == MouseButton.PRIMARY) {// get the position of the mouse point when user left click
Circle circle = makeCircle(drawX, drawY);// using the makeCircle method to draw the circle where the mouse is at the click
pane.getChildren().add(circle);
} else if (e.getButton() == MouseButton.SECONDARY) {
deleteCircle(drawX, drawY);// using the deleteCircle function to delete the circle if right click on the circle
}
});
pane.getChildren().add(polygon);
pane.getChildren().addListener(new ListChangeListener<Node>() {
#Override
public void onChanged(Change<? extends Node> c) {
int numOfCircles = pane.getChildren().size() - 1;
if ( numOfCircles >= 2 ) {
polygon.setStroke(Color.BLACK);
polygon.getPoints().clear();
for ( int i = 0; i <= numOfCircles; i++ ) {
Node node = pane.getChildren().get(i);
if ( node.getClass() == Circle.class ) {
polygon.getPoints().addAll(
((Circle) node).getCenterX(),
((Circle) node).getCenterY()
);
}
}
System.out.println(polygon.getPoints());
}
}
});
// container to show all context in a 500px by 500px windows
try {
Scene scene = new Scene(pane, 500, 500);// size of the scene
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
// method to draw the circle when left click
private Circle makeCircle(double drawX, double drawY) {
Circle circle = new Circle(drawX, drawY, 7, Color.CORAL);// create the circle and its properties(color: coral to see it better)
circle.setStroke(Color.BLACK);// create the stroke so the circle is more visible
return circle;
}
// method to delete the circle using the ObservableList class
private void deleteCircle(double deletX, double deleteY) {
// loop to create my list of circles 'til this moment
ObservableList<Node> list = pane.getChildren();
for (int i = list.size() - 1; i >= 0; i--) {
Node circle = list.get(i);
// checking which circle I want to delete
if (circle instanceof Circle && circle.contains(deletX, deleteY)) {
pane.getChildren().remove(circle);
break;
}
}
}
public static void main(String[] args) {
Application.launch(args);
}
}
You can also not use the change listener, but call the redraw whenever you add or delete a circle. In addition you can also add an onclick listener to each circle calling the delete function and deleting in a more efficient manner:
public class Main extends Application {
// using the base class of layout panes
Pane pane = new Pane();
Polygon polygon = new Polygon();
#Override
public void start(Stage primaryStage) {
// what to do when the mouse is clicked
pane.setOnMouseClicked(e -> {
double drawX = e.getX();// position of mouse in X axle
double drawY = e.getY();// position of mouse in y axle
if (e.getButton() == MouseButton.PRIMARY) {// get the position of the mouse point when user left click
Circle circle = makeCircle(drawX, drawY);// using the makeCircle method to draw the circle where the mouse is at the click
pane.getChildren().add(circle);
circle.setOnMouseClicked( event -> {
deleteCircle(circle);
// consume event so that the pane on click does not get called
event.consume();
});
redrawPolygon();
}
});
polygon = new Polygon();
polygon.setFill(Color.TRANSPARENT);
polygon.setStroke(Color.BLACK);
pane.getChildren().add(polygon);
// container to show all context in a 500px by 500px windows
try {
Scene scene = new Scene(pane, 500, 500);// size of the scene
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
// method to draw the circle when left click
private Circle makeCircle(double drawX, double drawY) {
Circle circle = new Circle(drawX, drawY, 7, Color.CORAL);// create the circle and its properties(color: coral to see it better)
circle.setStroke(Color.BLACK);// create the stroke so the circle is more visible
return circle;
}
private void redrawPolygon() {
int numOfCircles = pane.getChildren().size() - 1;
if ( numOfCircles > 0 ) {
polygon.getPoints().clear();
for ( int i = 0; i <= numOfCircles; i++ ) {
Node node = pane.getChildren().get(i);
if ( node.getClass() == Circle.class ) {
polygon.getPoints().addAll(
((Circle) node).getCenterX(),
((Circle) node).getCenterY()
);
}
}
}
}
private void deleteCircle(Circle circle){
pane.getChildren().remove(circle);
redrawPolygon();
}
public static void main(String[] args) {
Application.launch(args);
}
}
If you want to only use one click handler you could also do it this way:
pane.setOnMouseClicked(e -> {
if ( e.getTarget().getClass() == Circle.class ) {
deleteCircle((Circle)e.getTarget());
} else {
Circle circle = makeCircle(e.getX(), e.getY());// using the makeCircle method to draw the circle where the mouse is at the click
pane.getChildren().add(circle);
redrawPolygon();
}
});

Related

How to perform sequential animation

I'm creating a basic animation with javaFX, I have 5 rectangles in a row, I have two cirlces, red and blue. The red cricle is set on the first rectangle and the blue one is set on the fifth rectangle.
The idea is: If I click the first rectangle I want the red circle to travel to the fifth rectangle (by a translation) and once it gets there the blue rectangle (which is on the fifth rectangle) travels to the first one, in another word they exchange positions. I used the AnimationTimer class in my logic but the porblem is that the animation of both cirlces is synchronized when the pressedMouse event happens and that's not what I want, what I want is that the animation of the blue circle starts once the red circle's one is finished. I want to understand why is that happening? Is it kinda multiple thread? In case it is, when I run the program the red circle gets stuck in the middle however the blue one travels out of the bounds and hides, however if I comment one of the cirlce's position code for update (the update method) the app runs correctly, I hope I get an answer and I'm so thankful.
Another question is: How to make my animation looks smoother because it stops for a fraction of a second and moves again.
here is my code:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class animation extends Application {
AnchorPane root = new AnchorPane();
//create a matrix from rectangle class to stock 5 rectangle objects
rectangle rect [] = new rectangle [5];
//isMoving gets the true value when the animation starts
private boolean isMoving = false;
private int traveledDistance = 30;
#Override
public void start(Stage primaryStage) {
//add 5 rectangles on the anchorpane
//rect[0], rect[2] and rect[4] have BURLYWOOD color
//rect[1], rect[3] have DARKBLUE color
for(int i = 0; i<5; i++)
{
if(i%2 == 0)
{
rect[i] = new rectangle();
rect[i].setFill(Color.BURLYWOOD);
}
else
{
rect[i] = new rectangle();
rect[i].setFill(Color.DARKBLUE);
}
//set all 5 rectangles as empty
rect[i].setRectEmpty(true);
//set all the 5 rectangles one after the other along the x axis
rect[i].setTranslateX(i*60);
//add the 5 rectangles to the parent
root.getChildren().add(rect[i]);
}
//instantiation of two circles (c and d) from cirlce class
circle c = new circle(Color.RED);
c.setName("redCircle");
circle d = new circle(Color.BLUE);
d.setName("blueCircle");
//set the position of the red circle centered relatively to rect[0]
//rect[0] is no longer empty as it contains the red circle
c.setTranslateX(30);
c.setTranslateY(30);
rect[0].setCircle(c);
rect[0].setCircleName(c.getName());
rect[0].setRectEmpty(false);
root.getChildren().add(c);
//set the position of the blue circle centered relatively to rect[4]
d.setTranslateX(4*60 +30);
d.setTranslateY(30);
rect[4].setCircle(d);
rect[4].setCircleName(d.getName());
root.getChildren().add(d);
displayedScene(primaryStage);
//when the parent is clicked
root.setOnMousePressed(new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent event) {
//get the index of the clicked rectangle
int index = (int) event.getX()/60;
//if the clicked rectangle contains the red circle inside
if(!rect[index].isRectEmpty() && rect[index].getCircleName().equals("redCircle"))
{
Circle circle = rect[index].getCircle();
//update the postion of the red circle so that it occupies the last rectangle (rect[4])
update(index,5, circle);
//update the position of the blue circle so that it occupies the first rectangle(rect[0])
update(5,0, rect[4].getCircle());
}
}
});
}
//update method uses the AnimationTimer class
public void update(int initialPos, int lastPos, Circle circle)
{
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
updateCirclePosition(initialPos, lastPos, circle);
if(!isMoving)
{
this.stop();
}
}
};
timer.start();
}
public void updateCirclePosition(int initialPos, int lastPos, Circle circle)
{
int dx = 2;
if(initialPos>lastPos)
{
dx = -1*dx;
}
isMoving = true;
int distance = Math.abs((lastPos - initialPos)*60);
if(traveledDistance<distance-30)
{
circle.setTranslateX(circle.getTranslateX() + dx);
traveledDistance +=Math.abs(dx);
}
else{
isMoving = false;
traveledDistance = 30;
}
}
//load the Stage
public void displayedScene(Stage primaryStage)
{
Scene scene = new Scene(root, 300, 60);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
// circle class extends Circle
public class circle extends Circle
{
private String name;
public circle(Paint color) {
super(30, color);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
And here is rectangle class:
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
//rectangle class extends Rectangle
public class rectangle extends Rectangle {
private Circle circle;
private String circleName;
private boolean rectEmpty;
public rectangle() {
super(60, 60);
}
public Circle getCircle() {
return circle;
}
public void setCircle(Circle circle) {
this.circle = circle;
}
public boolean isRectEmpty() {
return rectEmpty;
}
public void setRectEmpty(boolean rectEmpty) {
this.rectEmpty = rectEmpty;
}
public String getCircleName() {
return circleName;
}
public void setCircleName(String circleName) {
this.circleName = circleName;
}
}
The following is an mre demonstrating the requested functionality.
Circles animation is done by animateCircles(). It uses TranslateTransition to translate a circle from one position to the other.
setOnFinished is used to start the next animation.
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Bounds;
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.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Animation extends Application {
private static final double SQUARE_SIZE = 60, RADIUS = SQUARE_SIZE /2, ANIMATION_TIME = 1;
private final Pane root = new Pane();
private final Rectangle rect [] = new Rectangle [5];
private final Circle circles [] = new Circle[2];
private boolean isMoving = false, isSwapped = false;
#Override
public void start(Stage primaryStage) {
for(int i = 0; i<rect.length; i++) {
rect[i] = new Rectangle(SQUARE_SIZE, SQUARE_SIZE, i%2 == 0 ? Color.BURLYWOOD : Color.DARKBLUE);
//set all the 5 rectangles one after the other along the x axis
rect[i].setTranslateX(i*SQUARE_SIZE);
root.getChildren().add(rect[i]);
}
circles[0] = new Circle(RADIUS,Color.RED);
circles[1] = new Circle(RADIUS,Color.BLUE);
//set the position of the red circle centered to rect[0]
Point2D center = centerOf(rect[0]);
circles[0].setTranslateX(center.getX());
circles[0].setTranslateY(center.getY());
//set the position of the blue circle centered to rect[4]
center = centerOf(rect[4]);
circles[1].setTranslateX(center.getX());
circles[1].setTranslateY(center.getY());
root.getChildren().add(circles[0]);
root.getChildren().add( circles[1]);
Scene scene = new Scene(root, SQUARE_SIZE*rect.length, SQUARE_SIZE);
primaryStage.setScene(scene);
primaryStage.show();
root.setOnMousePressed(event -> animateCircles());
}
//return the center point
private Point2D centerOf(Rectangle rect) {
Bounds bounds = rect.getBoundsInParent();
double x = bounds.getMinX() + 0.5 * bounds.getWidth();
double y = bounds.getMinY() + 0.5 * bounds.getHeight();
return new Point2D(x, y);
}
private void animateCircles() {
if(isMoving) return;
TranslateTransition translateCircle0 = new TranslateTransition(Duration.seconds(ANIMATION_TIME), circles[0]);
translateCircle0.setToX( isSwapped ? centerOf(rect[0]).getX() : centerOf(rect[4]).getX());
TranslateTransition translateCircle1 = new TranslateTransition(Duration.seconds(ANIMATION_TIME), circles[1]);
translateCircle1.setToX( isSwapped ? centerOf(rect[4]).getX() : centerOf(rect[0]).getX());
translateCircle0.setOnFinished(e-> {
translateCircle1.play();
});
translateCircle1.setOnFinished(e-> {
isMoving = false;
isSwapped = ! isSwapped;
});
isMoving = true;
translateCircle0.play();
}
public static void main(String[] args) {
launch(args);
}
}
Alternatively you could implement animateCircles() using SequentialTransition:
private void animateCircles() {
if(isMoving) return;
TranslateTransition translateCircle0 = new TranslateTransition(Duration.seconds(ANIMATION_TIME), circles[0]);
translateCircle0.setToX( isSwapped ? centerOf(rect[0]).getX() : centerOf(rect[4]).getX());
TranslateTransition translateCircle1 = new TranslateTransition(Duration.seconds(ANIMATION_TIME), circles[1]);
translateCircle1.setToX( isSwapped ? centerOf(rect[4]).getX() : centerOf(rect[0]).getX());
SequentialTransition sequentialTransition = new SequentialTransition(translateCircle0, translateCircle1);
isMoving = true;
sequentialTransition.play();
sequentialTransition.setOnFinished(e-> {
isMoving = false;
isSwapped = ! isSwapped;
});
}

Create an Ellipse in javavfx where the scaling is from the top left (like a Rectangle) rather than center

I have a javafx program that generates a canvas where a user can draw an Ellipse. I am using the press down, drag and release technique for the mouse.
However I want to be able to scale the shape in size from the top left corner of the shape (much like a Rectangle is scaled) rather than its center. Is there any suggestions to how I could achieve this?
#Override
public void start(Stage ellipseStage) {
//Create ellipse
ellipsePane = new Pane();
ellipsePane.setMinSize(600,600);
ellipsePane.setOnMousePressed(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
ellipse = new Ellipse();
ellipse.setCenterX(e.getX());
ellipse.setCenterY(e.getY());
ellipse.setStroke(Color.ORANGE);
ellipse.setFill(Color.BLACK);
ellipsePane.getChildren().add(ellipse);
}
//if we double click
if (e.getClickCount() == 2) {
ellipse = null;
}
});
//When the mouse is dragged the ellipse expands
ellipsePane.setOnMouseDragged(e -> {
if (ellipse != null) {
ellipse.setRadiusX(e.getX() - ellipse.getCenterX());
ellipse.setRadiusY(e.getY() - ellipse.getCenterY());
}
});
Scene scene = new Scene(ellipsePane);
ellipseStage.setScene(scene);
ellipseStage.show();
}
public static void main(String[] args) {
launch(args);
}}
One option is to keep track of the location of the original mouse press, then set the center X/Y properties of the Ellipse to always be the midpoint between the origin and where the mouse is currently (i.e. where it's dragged). The radii would be half the distance between the origin and the current location as well. Here's an example:
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Ellipse;
import javafx.stage.Stage;
public class Main extends Application {
private Pane pane;
private Point2D origin;
private Ellipse ellipse;
#Override
public void start(Stage primaryStage) {
pane = new Pane();
pane.setOnMousePressed(this::handleMousePressed);
pane.setOnMouseDragged(this::handleMouseDragged);
pane.setOnMouseReleased(this::handleMouseReleased);
primaryStage.setScene(new Scene(pane, 600.0, 400.0));
primaryStage.show();
}
private void handleMousePressed(MouseEvent event) {
event.consume();
origin = new Point2D(event.getX(), event.getY());
ellipse = new Ellipse(event.getX(), event.getY(), 0.0, 0.0);
pane.getChildren().add(ellipse);
}
private void handleMouseDragged(MouseEvent event) {
event.consume();
ellipse.setCenterX((origin.getX() + event.getX()) / 2.0);
ellipse.setCenterY((origin.getY() + event.getY()) / 2.0);
ellipse.setRadiusX(Math.abs(event.getX() - origin.getX()) / 2.0);
ellipse.setRadiusY(Math.abs(event.getY() - origin.getY()) / 2.0);
}
private void handleMouseReleased(MouseEvent event) {
event.consume();
ellipse = null;
origin = null;
}
}
So I presume what you mean is that when you drag the ellipse, the edge position changes but you want the edge position to stay the same and the center to move.
ellipsePane.setOnMouseDragged(e -> {
if (ellipse != null) {
double x0 = ellipse.getCenterX() - ellipse.getRadiusX();
double y0 = ellipse.getCenterY() - ellipse.getRadiusY();
//the new radii
double rxp = e.getX() - x0;
double ryp = e.getY() - y0;
//the new center positions. to keep the origin the same.
double cx = x0 + rxp;
double cy = y0 + ryp;
ellipse.setRadiusX(rxp);
ellipse.setRadiusY(ryp);
ellipse.setCenterX(cx);
ellipse.setCenterY(cy);
}
});

Get Object from Collection

I'm building a grid out of rectangles.
I want to click one of the rectangles and its color should change.
However, I dont know how to access the rectangles in Main AFTER they've been created.
Main:
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args) {
launch(args);
}
public void changeColor(Pane p) {
p.setOnMouseClicked(me -> {
double posX = me.getX();
double posY = me.getY();
int colX = (int)(posX / 30);
int colY = (int) (posY / 30);
ObservableList<Node> children = p.getChildren();
for( Node d : children) {
if(d.getLayoutX() == colX && d.getLayoutY() == colY) {
// how can i access my rectangle here?
// basically, i want to be able to do .setFill()
}
}
});
}
#Override
public void start(Stage primaryStage) throws Exception {
Grid g = new Grid(30,30, 30);
Pane window = g.render();
Scene scene = new Scene(window, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
this.changeColor(window);
}
}
Grid:
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
public class Grid {
Integer width, height, squareSize;
Color fill = Color.ALICEBLUE,
stroke = Color.BLACK;
public Grid(int x, int y, int squareSize){
this.width = x;
this.height = y;
this.squareSize = squareSize;
}
public Pane render() {
Pane p = new Pane();
Rectangle [][] rect = new Rectangle[this.width][this.height];
for(int i = 0; i < this.width; i++) {
for(int j = 0; j < this.height; j++) {
rect[i][j] = new Rectangle();
rect[i][j].setX(i * width);
rect[i][j].setY(j * height);
rect[i][j].setWidth(this.squareSize);
rect[i][j].setHeight(this.squareSize);
rect[i][j].setFill(this.fill);
rect[i][j].setStroke(this.stroke);
p.getChildren().add(rect[i][j]);
}
}
return p;
}
}
Can someone please help me to figure out how I can access my rectangles again in the main file?
Keeping with your current design, you simply need to test if the mouse clicked within a child and if that child is an instance of Rectangle; then you can cast and call setFill. However, I recommend changing the name of changeColor as that name does not represent what that method is doing.
public void installChangeColorHandler(Pane pane) {
pane.setOnMouseClicked(event -> {
for (Node child : pane.getChildren()) {
if (child instanceof Rectangle
&& child.contains(child.parentToLocal(event.getX(), event.getY()))) {
((Rectangle) child).setFill(/* YOUR COLOR */);
event.consume();
break;
}
}
});
}
Since the event handler is added to Pane the x and y mouse coordinates are relative to said Pane. But since your Rectangles are direct children of Pane we can call Node.parentToLocal to transform those coordinates into the Rectangle's space1. We then need to test if the bounds of the Rectangle contain those coordinates using Node.contains; if it does, change the fill.
That said, you may want to modify your code so that you're adding an/the EventHandler directly to the Rectangles. That way you can use Event.getSource(). For instance2:
public Pane render(EventHandler<MouseEvent> onClick) {
// outer loop...
// inner loop...
Rectangle r = new Rectangle();
// configure r...
r.setOnMouseClicked(onClick);
// end inner loop...
// end outer loop...
}
...
// may want to consume event
Pane window = new Grid(30, 30, 30).render(event ->
((Rectangle) event.getSource()).setFill(/* YOUR COLOR */));
1. Even if they weren't direct children you can still transform the coordinates into the local space. For example, you can use Node.sceneToLocal and the scene coordinates provided by the MouseEvent (i.e. getSceneX()/getSceneY()).
2. This is still staying close to your design. You may want to rethink things, however, into a proper MVC (or other) architecture. Applying MVC With JavaFx

JavaFX how to remove specific node by mouseSecondary button

I was confused by one of the exercises of my book. It requires me to create a circle on the position of my mouse arrow every time when I click Mouse Left button, and then delete this node if my mouse is just in this circle and I click the right button. Adding circle into pane is so easy, so I could finish it quickly but remove it quite hard, so I was trapped in this part, could someone add some codes in order to delete the circle?
package com.company;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import java.util.ArrayList;
public class AddOrDeletePoint extends Application {
#Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
double radius = 5;
pane.setOnMouseClicked(e -> {
double X = e.getSceneX();
double Y = e.getSceneY();
Circle circle = new Circle(X, Y, radius);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
if (e.getButton() == MouseButton.PRIMARY) {
pane.getChildren().add(circle);
} else if (e.getButton() == MouseButton.SECONDARY) {
pane.getChildren().remove(circle);//this is the remove part, but it does not work!
}
});
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
So just like this, how to remove the circle from the pane if my mouse stays on that circle and then click the right button?
You always create a circle. In case the secondary button is clicked, this circle was never added to the scene and nothing is removed from the child list of pane. You need to remove a existing circle.
Register the "Remove circle" listener to the circles you create:
pane.setOnMouseClicked(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
double X = e.getX(); // remove pane's coordinate system here
double Y = e.getY(); // remove pane's coordinate system here
final Circle circle = new Circle(X, Y, radius);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
circle.setOnMouseClicked(evt -> {
if (evt.getButton() == MouseButton.SECONDARY) {
evt.consume();
pane.getChildren().remove(circle);
}
});
pane.getChildren().add(circle);
}
});
Alternatively you could use the pick result:
pane.setOnMouseClicked(e -> {
if (e.getButton() == MouseButton.PRIMARY) {
double X = e.getX(); // remove pane's coordinate system here
double Y = e.getY(); // remove pane's coordinate system here
Circle circle = new Circle(X, Y, radius);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
pane.getChildren().add(circle);
} else if (e.getButton() == MouseButton.SECONDARY) {
// check if cicle was clicked and remove it if this is the case
Node picked = e.getPickResult().getIntersectedNode();
if (picked instanceof Circle) {
pane.getChildren().remove(picked);
}
}
});

How to make a node move whenever mouse is move over the scene (in JavaFX)?

I have written a small JavaFX program in which a Rectangle node is made to moved whenever mouse cursor is moved over the scene containing the rectangle. Here is my code:
public class MovedObjectWhenMouseMoved extends Application{
double nodeX;
double currentMousePos;
double oldMousePos = 0.0;
public static void main(String[] arg){
launch(arg);
}
#Override
public void start(Stage stage) throws Exception {
final Rectangle rect = new Rectangle(50, 50, Color.RED);
rect.setX(20);
rect.setY(20);
AnchorPane anchorPane = new AnchorPane();
anchorPane.getChildren().add(rect);
Scene scene = new Scene(anchorPane,500,500,Color.GREEN);
stage.setScene(scene);
stage.show();
scene.setOnMouseMoved(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
currentMousePos = mouseEvent.getX();
if(currentMousePos>oldMousePos){
rect.setX(rect.getX()+1); // Move right
}else if(currentMousePos<oldMousePos){
rect.setX(rect.getX()-1); // Move Left
}
oldMousePos = currentMousePos;
}
});
}
}
But here the problem is that the node speed is not same as the mouse speed.
How can I rectify this problem? Also please let me know if there is any better approach.
Mouse can change position on more then 1 pixel.
Try this code for handle:
currentMousePos = mouseEvent.getX();
double dX = currentMousePosition - oldMousePos;
rect.setX(rect.getX() + dX);
oldMousePos = currentMousePos;

Categories

Resources