I want to add a Sphere whenever I click inside a Rectangle. Basically, I've made this 9X6 Grid using Rectangles.Attached is my code, I don't know what to add inside ActionEventHandler.
public void Settings(ActionEvent event) throws Exception
{
Stage primaryStage = new Stage();
Parent root = FXMLLoader.load(getClass().getResource("/application/Settings.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
#FXML
ObservableList<Integer> comboList = FXCollections.observableArrayList(3,4,5,6,7,8);
ObservableList<String> gridList = FXCollections.observableArrayList("9 X 6","15 X 10");
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
combo.setItems(comboList);
gridb.setItems(gridList);
}
public void Grid() throws Exception {
Stage primaryStage=new Stage();
//AnchorPane root = new AnchorPane();
Group root = new Group();
Scene scene = new Scene(root);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
Rectangle r = null;
for(int i=0;i<9;i++) {
for(int j=0;j<6;j++) {
r = new Rectangle(70*j,70*i,70,70);
r.setStroke(Color.BLUE);
root.getChildren().add(r);
}
}
scene.setRoot(root);
primaryStage.show();
scene.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me) -> {
if(me.getButton().equals(MouseButton.PRIMARY)) {
Circle circle = new Circle(me.getX(), me.getY(), 10, Color.BLUE);
addEventHandler(root, circle);
root.getChildren().add(circle);
}
});}
private void addEventHandler(Group parent, Node node) {
// TODO Auto-generated method stub
node.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me) -> {
if(me.getButton().equals(MouseButton.SECONDARY)) {
parent.getChildren().remove(node);
}
});
}
If I use scene.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me) this code, then I can add Circles (or Spheres) Anywhere randomly wherever I click even on the Grid Lines. I just want to have a single Sphere for a particular Rectangle.
Either you add event handlers to the individual Rectangles or you use the pickResult property of the MouseEvent to check, if a Rectangle was clicked:
public static Rectangle getIntersectedRect(MouseEvent event) {
Node n = event.getPickResult().getIntersectedNode();
return (n instanceof Rectangle) ? (Rectangle) n : null;
}
scene.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me) -> {
if(me.getButton().equals(MouseButton.PRIMARY)) {
Rectangle rect = getIntersectedRect(me);
if (rect != null) {
Circle circle = new Circle(rect.getX()+35, rect.getY()+35, 10, Color.BLUE);
addEventHandler(root, circle);
root.getChildren().add(circle);
}
}
});}
Related
I want to create an application with a button and a colour picker on the top and a canvas in the centre of a BorderPane. I created a main Class TestSceneBuilder and 2 listeners: one for the button and one for the ColorPicker. The question is: when I detect change in colour how do I pass it to my CerchioListener ?
Main Class:
public class TestSceneBuilder extends Application {
final int H = 300, W = 300; //height and width
BorderPane root;
#Override
public void start(Stage primaryStage) {
root = this.setScene();
Scene scene = new Scene(root, H, W);
primaryStage.setTitle("Test");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* This method is supposed to build the scene with all components:
* a button "Draw" that draws the rectangle
* a canvas
* a colorPicker
* #return
*/
BorderPane setScene(){
BorderPane border = new BorderPane();
final ColorPicker cp = new ColorPicker(Color.AQUA);
Canvas canvas = new Canvas(H, W);
Button btn = new Button("Draw");
/*CerchioListner should get the mouse clicked event and draw the circle*/
final CerchioListner l = new CerchioListner(canvas, cp.getValue());
btn.addEventHandler(MouseEvent.MOUSE_CLICKED, l);
/*ColorListener intercept the color change in ColorPicker cp and change the color of the
shape drawn*/
ColorListener cl = new ColorListener(cp);
cp.setOnAction(cl);
HBox hb = new HBox();
hb.getChildren().addAll(btn, cp);
border.setTop(hb);
BorderPane.setAlignment(hb, Pos.CENTER);
border.setCenter(canvas);
return border;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Button listener: CerchioListener
public class CerchioListner implements javafx.event.EventHandler{
Canvas canvas = null;
Color colore;
public CerchioListner(Canvas c, Color colore) {
this.canvas = c;
this.colore = colore;
}
public void changeColor(Color c) {
this.colore = c;
}
#Override
public void handle(Event t) {
disegna();
}
public void disegna(){
canvas.getGraphicsContext2D().setFill(colore);
canvas.getGraphicsContext2D().fillOval(20, 20, 20, 20);
}
}
Color Picker listener: ColorListener
public class ColorListener implements javafx.event.EventHandler{
ColorPicker cp = null;
public ColorListener(ColorPicker cp) {
this.cp = cp;
}
#Override
public void handle(Event t) {
Color c = cp.getValue();
System.out.println("handle CP "+cp.getValue());
//restituisciColoreSelezionato(c);
}
/*public Color restituisciColoreSelezionato(Color c){
return c;
}*/
}
There are several things that is not the best you can have:
You have a Canvas, which is not member of Main, just a local variable in setScene(), therefore it is only accessible in that method. As the Canvas is the most important part of your class, you should have it as a class member because you want to access it anywhere from the class.
The listener for the Button should not store any reference to the selected color and to the Canvas, it is stored by Main and the listener should use that member.
The listener of the ColorPicker should not store any reference to the ColorPicker itself. The ColorPicker should be a member to make it able to access the currently selected color anywhere in Main.
I have updated your code to include these modifications:
public class TestSceneBuilder extends Application {
final int H = 300, W = 300;
BorderPane root;
Canvas canvas;
ColorPicker cp;
Button btn;
#Override
public void start(Stage primaryStage) {
root = this.setScene();
Scene scene = new Scene(root, H, W);
primaryStage.setTitle("Test");
primaryStage.setScene(scene);
primaryStage.show();
}
BorderPane setScene(){
BorderPane border = new BorderPane();
cp = new ColorPicker(Color.AQUA);
canvas = new Canvas(H, W);
btn = new Button("Draw");
btn.setOnAction((event) -> {
canvas.getGraphicsContext2D().setFill(cp.getValue());
canvas.getGraphicsContext2D().fillOval(20, 20, 20, 20);
});
HBox hb = new HBox();
hb.getChildren().addAll(btn, cp);
border.setTop(hb);
BorderPane.setAlignment(hb, Pos.CENTER);
border.setCenter(canvas);
return border;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
If you want to stay with external listeners:
Exchange this:
btn.setOnAction((event) -> {
canvas.getGraphicsContext2D().setFill(cp.getValue());
canvas.getGraphicsContext2D().fillOval(20, 20, 20, 20);
});
with
CerchioListener cerchioListener = new CerchioListener(canvas);
btn.setOnAction(cerchioListener);
cerchioListener.colorProperty.bind(cp.valueProperty());
and add the listener:
CerchioListener.java
public class CerchioListener implements EventHandler<ActionEvent> {
private Canvas canvas = null;
public ObjectProperty<Color> colorProperty = new SimpleObjectProperty<Color>(Color.WHITE);
public CerchioListener(Canvas c) {
this.canvas = c;
}
public Canvas getCanvas() {
return canvas;
}
public void setCanvas(Canvas canvas) {
this.canvas = canvas;
}
#Override
public void handle(ActionEvent t) {
canvas.getGraphicsContext2D().setFill(colorProperty.get());
canvas.getGraphicsContext2D().fillOval(20, 20, 20, 20);
}
}
I want to make a ScrollPane with a custom Pane inside, that has two Children. One that holds my objects and one just for the background. I want to make it so if I zoom out, and the content is smaller than the viewport, then the size of the content would expand, filling in the new place in the viewport. And if I zoom back then it would remain the same, and I have now a larger content in area. The new width of the content would be: originalWidth + viewportWidth - scaledWidth.
I have made the grid, and the zooming works, but I can't make it so that it resizes the content. I have tried to set the content size when zooming to the current viewport size, but it does not work.
Question:
What am I doing wrong?
The layout is defined in fxml. Another than ScrollPane content set to fill height and width nothing out of ordinary there.
CustomPane class:
public class CustomPane extends StackPane implements Initializable {
#FXML
StackPane view;
#FXML
AnchorPane objectPane;
#FXML
GriddedPane background;
private DoubleProperty zoomFactor = new SimpleDoubleProperty(1.5);
private BooleanProperty altStatus = new SimpleBooleanProperty(false);
public CustomPane() {
super();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getClassLoader().getResource("CustomCanvas.fxml"));
loader.setController(this);
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void initialize(URL location, ResourceBundle resources) {
objectPane.setStyle("-fx-background-color: transparent");
objectPane.prefWidthProperty().bind(prefWidthProperty());
objectPane.prefHeightProperty().bind(prefHeightProperty());
objectPane.getChildren().add(new Circle(512, 378, 20, Color.RED));
}
public void zoom(ScrollPane parent, Node node, double factor, double x, double y) {
Timeline timeline = new Timeline(60);
// determine scale
double oldScale = node.getScaleX();
double scale = oldScale * factor;
double f = (scale / oldScale) - 1;
// determine offset that we will have to move the node
Bounds bounds = node.localToScene(node.getBoundsInLocal());
double dx = (x - (bounds.getWidth() / 2 + bounds.getMinX()));
double dy = (y - (bounds.getHeight() / 2 + bounds.getMinY()));
// timeline that scales and moves the node
timeline.getKeyFrames().clear();
timeline.getKeyFrames().addAll(
new KeyFrame(Duration.millis(100), new KeyValue(node.translateXProperty(), node.getTranslateX() - f * dx)),
new KeyFrame(Duration.millis(100), new KeyValue(node.translateYProperty(), node.getTranslateY() - f * dy)),
new KeyFrame(Duration.millis(100), new KeyValue(node.scaleXProperty(), scale)),
new KeyFrame(Duration.millis(100), new KeyValue(node.scaleYProperty(), scale))
);
timeline.play();
Bounds viewportBounds = parent.getViewportBounds();
if (bounds.getWidth() < viewportBounds.getWidth()) {
setMinWidth(viewportBounds.getWidth());
requestLayout();
}
if (getMinHeight() < viewportBounds.getHeight()) {
setMinHeight(viewportBounds.getHeight());
requestLayout();
}
}
public final Double getZoomFactor() {
return zoomFactor.get();
}
public final void setZoomFactor(Double zoomFactor) {
this.zoomFactor.set(zoomFactor);
}
public final DoubleProperty zoomFactorProperty() {
return zoomFactor;
}
public boolean getAltStatus() {
return altStatus.get();
}
public BooleanProperty altStatusProperty() {
return altStatus;
}
public void setAltStatus(boolean altStatus) {
this.altStatus.set(altStatus);
}
}
Controller class:
public class Controller implements Initializable {
public ScrollPane scrollPane;
public CustomPane customPane;
public AnchorPane anchorPane;
public Tab tab1;
#Override
public void initialize(URL location, ResourceBundle resources) {
scrollPane.viewportBoundsProperty().addListener((observable, oldValue, newValue) -> {
customPane.setMinSize(newValue.getWidth(), newValue.getHeight());
});
scrollPane.requestLayout();
tab1.getTabPane().addEventFilter(KeyEvent.KEY_PRESSED, event1 -> {
if (event1.getCode() == KeyCode.ALT)
customPane.setAltStatus(true);
});
tab1.getTabPane().addEventFilter(KeyEvent.KEY_RELEASED, event1 -> {
if (event1.getCode() == KeyCode.ALT)
customPane.setAltStatus(false);
});
scrollPane.setOnScroll(event -> {
double zoomFactor = 1.5;
if (event.getDeltaY() <= 0)
zoomFactor = 1 / zoomFactor;
customPane.setZoomFactor(zoomFactor);
if (customPane.getAltStatus())
customPane.zoom(scrollPane, customPane, customPane.getZoomFactor(), event.getSceneX(), event.getSceneY());
});
}
}
GriddedPane class:
public class GriddedPane extends Pane implements Initializable {
DoubleProperty gridWidth = new SimpleDoubleProperty(this, "gridWidth", 10);
DoubleProperty gridHeight = new SimpleDoubleProperty(this, "gridHeight", 10);
public GriddedPane() {
super();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
#Override
protected void layoutChildren() {
getChildren().clear();
setMouseTransparent(true);
toBack();
for (int i = 0; i < getHeight(); i += getGridWidth())
getChildren().add(makeLine(0, i, getWidth(), i, "x"));
for (int i = 0; i < getWidth(); i += getGridHeight())
getChildren().add(makeLine(i, 0, i, getHeight(), "y"));
}
public void redrawLines() {
for (Node n : getChildren()) {
Line l = (Line) n;
if (l.getUserData().equals("x")) {
l.setEndX(getWidth());
} else if (l.getUserData().equals("y")) {
l.setEndY(getHeight());
}
}
}
private Line makeLine(double sx, double sy, double ex, double ey, String data) {
final Line line = new Line(sx, sy, ex, ey);
if (ex % (getGridWidth() * 10) == 0.0) {
line.setStroke(Color.BLACK);
line.setStrokeWidth(0.3);
} else if (ey % (getGridHeight() * 10) == 0.0) {
line.setStroke(Color.BLACK);
line.setStrokeWidth(0.3);
} else {
line.setStroke(Color.GRAY);
line.setStrokeWidth(0.1);
}
line.setUserData(data);
return line;
}
public double getGridWidth() {
return gridWidth.get();
}
public DoubleProperty gridWidthProperty() {
return gridWidth;
}
public void setGridWidth(double gridWidth) {
this.gridWidth.set(gridWidth);
}
public double getGridHeight() {
return gridHeight.get();
}
public DoubleProperty gridHeightProperty() {
return gridHeight;
}
public void setGridHeight(double gridHeight) {
this.gridHeight.set(gridHeight);
}
}
Not really sure if I unterstood what you want to achieve. But if your goal is to make the content of the scrollPane never get smaller than the scrollPane's width, this does the job for me:
public class Zoom extends Application {
#Override
public void start(Stage primaryStage) {
ImageView imageView = new ImageView(new Image(someImage));
ScrollPane scrollPane = new ScrollPane(imageView);
StackPane root = new StackPane(scrollPane);
imageView.fitWidthProperty().bind(scrollPane.widthProperty());
imageView.fitHeightProperty().bind(scrollPane.heightProperty());
scrollPane.setOnScroll(evt -> {
boolean zoomOut = evt.getDeltaY() < 0;
double zoomFactor = zoomOut ? -0.2 : 0.2;
imageView.setScaleX(imageView.getScaleX() + zoomFactor);
imageView.setScaleY(imageView.getScaleY() + zoomFactor);
if (zoomOut) {
Bounds bounds = imageView.getBoundsInParent();
if (bounds.getWidth() < scrollPane.getWidth()) {
imageView.setScaleX(1);
imageView.setScaleY(1);
}
}
});
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I am quite beginner in Java and need some help with my application.
I am would like to use drag and drop on custom made shapes with javafx canvas i.e multiple polygons that make up a bow tie.
I have created a method that draws a bow tie that looks like this:
public void joonistaBowTie(GraphicsContext gc) {
// Bowtie left side
gc.setFill(Color.RED);
double xpoints[] = { 242, 242, 200 };
double ypoints[] = { 245, 290, 270 };
int num = 3;
gc.fillPolygon(xpoints, ypoints, num);
// Bowtie right side
gc.setFill(Color.RED);
double xpoints1[] = { 160, 160, 200 };
double ypoints1[] = { 245, 290, 270 };
int num1 = 3;
gc.fillPolygon(xpoints1, ypoints1, num1);
// Bowtie middle part
gc.setFill(Color.RED);
gc.fillOval(190, 255, 20, 30);
}
I have moved that method into a separate class called BowTie.
I also have a main class that looks like this:
public class GraafikaNaide extends Application {
Bowtie bowtie;
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX-iga joonistatud kloun");
Group root = new Group();
Canvas canvas = new Canvas(1000, 1000);
GraphicsContext gc = canvas.getGraphicsContext2D();
joonista(gc);
root.getChildren().add(canvas);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private void joonista(GraphicsContext gc) {
Bowtie bowtie = new Bowtie();
bowtie.joonistaBowTie(gc);
}
I also found somewhat example on how to do drag and drop, but i just lack knowledge on how to implement this code to mine.
Could someone please help me with this?
Thanks
Using the link you provided, here is how you would incorporate it with your work:
public class GraafikaNaide extends Application
{
joonistaBowTie bowtie;
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;
#Override
public void start(Stage primaryStage)
{
Canvas canvas = new Canvas(1000, 1000);
GraphicsContext gc = canvas.getGraphicsContext2D();
joonista(gc);
canvas.setOnMousePressed(canvasOnMousePressedEventHandler);
canvas.setOnMouseDragged(canvasOnMouseDraggedEventHandler);
Group root = new Group();
root.getChildren().add(canvas);
primaryStage.setTitle("JavaFX-iga joonistatud kloun");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
private void joonista(GraphicsContext gc)
{
joonistaBowTie bowtie = new joonistaBowTie();
bowtie.joinBowTie(gc);
}
EventHandler<MouseEvent> canvasOnMousePressedEventHandler = new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent mouseEvent)
{
orgSceneX = mouseEvent.getSceneX();
orgSceneY = mouseEvent.getSceneY();
orgTranslateX = ((Canvas)(mouseEvent.getSource())).getTranslateX();
orgTranslateY = ((Canvas) (mouseEvent.getSource())).getTranslateY();
}
};
EventHandler<MouseEvent> canvasOnMouseDraggedEventHandler = new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent mouseEvent)
{
double offsetX = mouseEvent.getSceneX() - orgSceneX;
double offsetY = mouseEvent.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
((Canvas) (mouseEvent.getSource())).setTranslateX(newTranslateX); //transform the object
((Canvas) (mouseEvent.getSource())).setTranslateY(newTranslateY);
}
};
}
Hope this helps.
I am trying to learn javafx. I did most of the code but I am having trouble with the start method.
What I wanted to do was add spots to the screen by clicking on it. And if I press either 1 or 0 future spots that will be added will change to some different color. Therefore, I know that I must use setOnMouseClicked
and setOnKeyPressed methods but there isn't much on the internet on it.
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class Spots extends Application {
public static final int SIZE = 500;
public static final int SPOT_RADIUS = 20;
private LinkedList<Spot> spotList;
private Color color;
public static void main(String...args) {
launch(args);
}
public void start(Stage stage) {
stage.setTitle("Spots");
dotList = new SinglyLinkedList<>();
Group root = new Group();
Scene scene = new Scene(root, 500, 500, Color.BLACK);
Spot r;
// ...
stage.show();
}
private class Spot extends Circle {
public Spot(double xPos, double yPos) {
super(xPos, yPos, SPOT_RADIUS);
setFill(color);
}
public boolean contains(double xPos, double yPos) {
double dx = xPos - getCenterX();
double dy = yPos - getCenterY();
double distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
return distance <= SPOT_RADIUS;
}
}
}
The reason the circle is not accepting is that it is not focused. For nodes to respond to key events they should be focusTraversable. You can do that by
calling setFocusTraversable(true) on the node. I edited your start() method and here is the code I ended up with.
public void start(Stage primaryStage) throws Exception {
Pane pane = new Pane();
final Scene scene = new Scene(pane, 500, 500);
final Circle circle = new Circle(250, 250, 20);
circle.setFill(Color.WHITE);
circle.setStroke(Color.BLACK);
pane.getChildren().add(circle);
circle.setFocusTraversable(true);
circle.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if ((e.getCode() == KeyCode.UP) && (circle.getCenterY() >= 5)) {
circle.setCenterY(circle.getCenterY() - 5);
}
else if ((e.getCode() == KeyCode.DOWN && (circle.getCenterY() <= scene.getHeight() - 5))) {
circle.setCenterY(circle.getCenterY() + 5);
}
else if ((e.getCode() == KeyCode.RIGHT) && (circle.getCenterX() <= scene.getWidth() - 5)) {
circle.setCenterX(circle.getCenterX() + 5);
}
else if ((e.getCode() == KeyCode.LEFT && (circle.getCenterX() >= 5))) {
circle.setCenterX(circle.getCenterX()-5);
}
}
});
//creates new spots by clicking anywhere on the pane
pane.setOnMouseClicked(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
double newX = event.getX(); //getting the x-coordinate of the clicked area
double newY = event.getY(); //getting the y-coordinate of the clicked area
Circle newSpot = new Circle(newX, newY,20);
newSpot.setFill(Color.WHITE);
newSpot.setStroke(Color.BLACK);
pane.getChildren().add(newSpot);
}
});
primaryStage.setTitle("Move the circle");
primaryStage.setScene(scene);
primaryStage.show();
}
Also take look at the answers for the following links:
Handling keyboard events
Cannot listen to KeyEvent in
JavaFX
Solution Approach
You can monitor the scene for key typed events and switch the color mode based on that. You can place an mouse event handler on your scene root pane and add a circle (of the appropriate color for the prevailing color mode) to the scene when the user clicks anywhere in the pane.
Sample Code
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
// Java 8+ code.
public class Spots extends Application {
private static final int SIZE = 500;
private static final int SPOT_RADIUS = 20;
private Color color = Color.BLUE;
public void start(Stage stage) {
Pane root = new Pane();
root.setOnMouseClicked(event ->
root.getChildren().add(
new Spot(
event.getX(),
event.getY(),
color
)
)
);
Scene scene = new Scene(root, SIZE, SIZE, Color.BLACK);
scene.setOnKeyTyped(event -> {
switch (event.getCharacter()) {
case "0":
color = Color.BLUE;
break;
case "1":
color = Color.RED;
break;
}
});
stage.setScene(scene);
stage.show();
}
private class Spot extends Circle {
public Spot(double xPos, double yPos, Color color) {
super(xPos, yPos, SPOT_RADIUS);
setFill(color);
}
}
public static void main(String... args) {
launch(args);
}
}
Further Info
For detailed information on event handling in JavaFX, see the Oracle JavaFX event tutorial.
Generally, you'd use setOnAction as shown in the Oracle tutorials.
Example:
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Hello World");
}
});
If the particular Node you're trying to use does not have a clickHandler method, try doing something like this (on Group for example):
group.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Hello!");
}
});
I want add some circles in border of a rectangle in event onMouseMoved.
Need to develop a graph using JavaFX and these circles will serve to connect the edges to the graph nodes.
See the image below:
I'm using JavaFX.
See you the code:
public class SampleDragAndDrop extends Application {
public static void main(String[] args) throws Exception {
launch(args);
}
#Override
public void start(final Stage stage) throws Exception {
DoubleProperty entity1X = new SimpleDoubleProperty(100);
DoubleProperty entity1Y = new SimpleDoubleProperty(100);
Entity entity1 = new Entity(Color.STEELBLUE, entity1X, entity1Y);
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
stage.setX(bounds.getMinX());
stage.setY(bounds.getMinY());
stage.setWidth(bounds.getWidth());
stage.setHeight(bounds.getHeight());
stage.setTitle("Draw circle in rectangle");
stage.setScene(new Scene(new Group(entity1), 400, 400, Color.ALICEBLUE));
stage.show();
}
class Anchor extends Circle {
Anchor(Color color, DoubleProperty x, DoubleProperty y) {
super(x.get(), y.get(), 20);
setFill(color.deriveColor(1, 1, 1, 0.5));
setStroke(color);
setStrokeWidth(2);
setStrokeType(StrokeType.OUTSIDE);
x.bind(centerXProperty());
y.bind(centerYProperty());
}
class Entity extends Rectangle {
Entity(Color color, DoubleProperty x, DoubleProperty y) {
setX(x.get());
setY(y.get());
setWidth(120);
setHeight(50);
setFill(color.deriveColor(1, 1, 1, 0.5));
setStroke(color);
setStrokeWidth(2);
setStrokeType(StrokeType.OUTSIDE);
setArcWidth(20);
setArcHeight(20);
x.bind(xProperty());
y.bind(yProperty());
enableDrag();
}
private void enableDrag() {
final Entity.Delta dragDelta = new Entity.Delta();
setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = getX() - mouseEvent.getX();
dragDelta.y = getY() - mouseEvent.getY();
getScene().setCursor(Cursor.MOVE);
}
});
setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
getScene().setCursor(Cursor.HAND);
}
});
setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
double newX = mouseEvent.getX() + dragDelta.x;
if (newX > 0 && newX < getScene().getWidth()) {
setX(newX);
}
double newY = mouseEvent.getY() + dragDelta.y;
if (newY > 0 && newY < getScene().getHeight()) {
setY(newY);
}
}
});
setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
getScene().setCursor(Cursor.HAND);
}
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
getScene().setCursor(Cursor.DEFAULT);
}
}
});
setOnMouseMoved(new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent mouseEvent) {
// Create circles in rectangle here
}
});
}
private class Delta {
double x, y;
}
}
}
How can I do?
Thank you!
This works:
// Create circles in rectangle here
// Not sure you really need these?
DoubleProperty leftX = new SimpleDoubleProperty();
DoubleProperty leftY = new SimpleDoubleProperty();
Anchor leftAnchor = new Anchor(Color.STEELBLUE, leftX, leftY);
leftAnchor.centerXProperty().bind(xProperty());
leftAnchor.centerYProperty().bind(yProperty().add(heightProperty().divide(2)));
((Group)getParent()).getChildren().add(leftAnchor);