Events for two overlay shapes - javafx

My problem:
I have a two overlay shapes, for example, two rectangles: A and B.
When B overlay A rectangle.
I add setOnMouseMoved handlers for both and i see that events handles only by top figure.
Code example:
public class MainExample extends Application {
#Override
public void start(Stage stage) {
stage.setMinWidth(700);
stage.setMaxWidth(700);
stage.setMinHeight(800);
stage.setMaxHeight(800);
StackPane root = new StackPane();
var a = new Rectangle(300, 300, Color.BLUE);
var b = new Rectangle(200, 200);
root.getChildren().addAll(a, b);
b.setOnMouseMoved(mouseEvent -> {
System.out.println("Mouse moved b!");
});
a.setOnMouseMoved(mouseEvent -> System.out.println("Mouse moved a!"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
What i want:
In the area of overlapping figures mouse moved events handles both of figures: A and B.
Thanx everyone for help!

I replace both mouse events to just one in stackpane node . The event checks if mouse coords is inside in both bounds (node a and node b) . When the mouse is in an area that intersetcs both rectangles the event wil thrigger both print statments
public class MainExample extends Application {
#Override
public void start(Stage stage) {
stage.setMinWidth(700);
stage.setMaxWidth(700);
stage.setMinHeight(800);
stage.setMaxHeight(800);
StackPane root = new StackPane();
var a = new Rectangle(300, 300, Color.BLUE);
var b = new Rectangle(200, 200);
root.getChildren().addAll(a, b);
root.setOnMouseMoved(mouseEvent -> {
if(b.getBoundsInParent().contains(mouseEvent.getSceneX(),mouseEvent.getSceneY())){
System.out.println("Mouse moved b!");}
if(a.getBoundsInParent().contains(mouseEvent.getSceneX(),mouseEvent.getSceneY())){
System.out.println("Mouse moved a!");}
});
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

Related

JavaFX button unselect

I'm trying to make a sprite editor using JavaFX using buttons as the pixels. I am able to change the colour of each button on press, but I'm trying to get it so if I click and drag I can paint multiple pixels.
The problem I'm finding is that after clicking and holding onto a button, I am unable to select the new button when I move the mouse over new button to select that one too. If I click and drag re-entering that button I can get the "Paint Dragged Pixel" debug message, but not if I enter a new pixel with the mouse down, which is what I want. Also I can get the pixel button to print "Entered Pixel" when the mouse enters any button, but not for when I click and drag to a new pixel.
I think the problem is that when I click on one pixel I am locked in, and unable to select a new pixel by hovering over a new one. Is there a way to unbind this selection, or is the problem a different one.
Main Application:
public class Main extends Application {
boolean mousePressed = false;
public boolean isMousePressed() {
return mousePressed;
}
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane borderPane = new BorderPane();
primaryStage.setTitle("SpriteSheet");
Group root = new Group();
Scene scene = new Scene(borderPane, 500,200);
scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
GridPane gridPane = new GridPane();
borderPane.setCenter(root);
for(int x = 0; x < 10; x++)
{
for(int y = 0; y < 10; y++) {
PixelButton button = new PixelButton();
button.setParentMain(this);
button.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
mousePressed = true;
System.out.println("mouseDown");
}
});
button.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
mousePressed = false;
System.out.println("mouseUp");
}
});
gridPane.add(button, x, y);
}
}
root.getChildren().add(gridPane);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The class for the PixelButton.
public class PixelButton extends Button {
Main parentMain;
public void setParentMain(Main parent) {
parentMain = parent;
}
public PixelButton() {
this.setMinSize(10, 10);
this.setPrefSize(10, 10);
this.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
}
});
this.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Entered Pixel");
if(parentMain.isMousePressed()){
System.out.println("Paint Dragged Pixel");
}
}
});
}
}
Thank you in advance.
Ok so I have been thinking about this one for a bit and have finally come up with a solution I simplified my solution a bit and used rectangles instead of buttons but you can transfer most of the code to the buttons as well so to start with this is not the exact functionality you were looking for but as close as I could get basically I fire an event on mouse press that releases the mouse click and as long as that event is not coming from the rectangle then dont flip the painting boolean paint and so you basically click to enter a "Paint Mode" and click again to get out of coloring tiles
public class Main extends Application {
private boolean mousePressed;
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane borderPane = new BorderPane();
primaryStage.setTitle("SpriteSheet");
Group root = new Group();
Scene scene = new Scene(borderPane, 500,200);
// scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
GridPane gridPane = new GridPane();
borderPane.setCenter(root);
for(int x = 0; x < 10; x++) {
for(int y = 0; y < 10; y++) {
Rectangle rectangle = new Rectangle(10, 10);
rectangle.setOnMousePressed(event -> {
mousePressed = true;
System.out.println("mouseDown");
rectangle.fireEvent(new MouseEvent(MouseEvent.MOUSE_RELEASED,
rectangle.getLayoutX(), rectangle.getLayoutY(), rectangle.getLayoutX(), rectangle.getLayoutY(),
MouseButton.PRIMARY, 1,
false, false, false, false,
false, false, false, false,
false, false, null));
});
rectangle.setOnMouseReleased(event -> {
System.out.println(event.getSource());
if(!event.getSource().toString().equals("Rectangle[x=0.0, y=0.0, width=10.0, height=10.0, fill=0x000000ff]")) {
mousePressed = false;
System.out.println("mouseUp");
}
});
rectangle.setOnMouseMoved(event -> {
if(mousePressed) {
rectangle.setFill(Color.BLUE);
}
});
gridPane.add(rectangle, x, y);
}
}
root.getChildren().add(gridPane);
primaryStage.show();
}
public static void main(String[] args) { launch(args); }
}

Why can't I println "left" when left arrow is pressed?

public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
Scene scene = new Scene(root, 400, 400);
EventHandler eventHandler = new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
System.out.println("handle");
if(event.getCode().equals(KeyCode.LEFT)) {
System.out.println("left");
}
}
};
Circle circle = new Circle(200,200,100);
circle.setFill(Color.AQUAMARINE);
circle.setOnKeyPressed(eventHandler);
root.getChildren().add(circle);
stage.setTitle("JavaFX GUI");
stage.setScene(scene);
stage.show();
}
Why can't I println "left" when left arrow is pressed ? I don't understand... It is a JavaFX Application...
I want that when I type left arrow in my keyboard, this prinln "left"
You added the listener to a Node that doesn't receive the focus. Add it to the Scene instead:
scene.setOnKeyPressed(eventHandler);
or set the focusTraversable property of the Circle to true:
circle.setFocusTraversable(true);

How can I assign an EventListener to a Path in javafx?

I have this piece of code which doesn't work correctly.
I want to set a listener for when a user clicks inside the square, yet
neither the pop-up nor the message "clicked" are displayed when I click
inside the square.
What am I missing?
This method is inside the Coords class.
public static void drawMyShape(final GraphicsContext ctx) {
Path path = new Path();
MoveTo mT = new MoveTo();
LineTo lT[] = new LineTo[4];
mT.setX(200.0);
mT.setY(200.0);
lT[0] = new LineTo(400.0, 200.0);
lT[1] = new LineTo(400.0, 400.0);
lT[2] = new LineTo(200.0, 400.0);
lT[3] = new LineTo(200.0, 200.0);
path.setStroke(Color.BEIGE);
path.getElements().addAll(mT, lT[0], lT[1], lT[2], lT[3]);
path.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
final Stage dialog = new Stage();
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.initOwner(Main.prim_stage);
VBox box = new VBox(20);
box.getChildren().add(new Text("Hey"));
Scene s = new Scene(box, 300, 200);
dialog.setScene(s);
dialog.show();
System.out.println("Clicked");
}
});
ctx.setLineWidth(4.0);
ctx.beginPath();
ctx.moveTo(mT.getX(), mT.getY());
for (int i = 0; i < lT.length; i++) {
ctx.lineTo(lT[i].getX(), lT[i].getY());
}
ctx.closePath();
ctx.stroke();
}
EDITED ON SUGGESTION by users.
So his is the main program:
public class Main extends Application {
public static Pane root;
private static Canvas main_canvas;
private static GraphicsContext ctx;
private static Rectangle2D bounds;
private static Scene scene;
public static Stage prim_stage;
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Switzerland Advertising");
initElements(primaryStage);
Coords.drawMyShape(ctx);
primaryStage.show();
System.out.println("Launched");
}
public static void main(String[] args) {
launch(args);
}
}
Everything is instanciated inside the following function, which works correctly and displays a full screen application with a canvas and a square drawn into it (image at the bottom).
private void initElements(final Stage primaryStage) {
prim_stage = primaryStage;
// ----------------------------------------
bounds = Screen.getPrimary().getVisualBounds();
double w = bounds.getWidth();
double h = bounds.getHeight();
// ----------------------------------------
// init elements of scene
root = new Pane();
main_canvas = new Canvas(w, h);
// ----------------------------------------
// init scene elements
scene = new Scene(root, w, h);
primaryStage.setX(bounds.getMinX());
primaryStage.setY(bounds.getMinY());
primaryStage.setWidth(w);
primaryStage.setHeight(h);
primaryStage.setScene(scene);
// ----------------------------------------
ctx = main_canvas.getGraphicsContext2D();
// set elements in main pane
root.getChildren().add(main_canvas);
// ----------------------------------------
}
So how can I make the pop-up window appear whenever I click inside the region drawn on the canvas?
This is the program
Your path is just a local variabl within your method. It has to be attached to the scene graph in order to get events. But when you attach it to the scene graph, drawing the same path on a canvas also does not make much sense.

How to write a MouseListener for JavaFX

I want to write a little game where I shoot from an object to a specific direction on a JavaFX Panel using my mouse position.
I want to turn a Line in the direction where my Mouse is.
Line line = new Line(startPosX, startPosY, mouseDirectionX, mouseDirectionY);
How can I do that?
Add a MOUSE_MOVED event filter like this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = new Pane();
Line line = new Line( 400,200,400,200);
root.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {
line.setEndX(e.getSceneX());
line.setEndY(e.getSceneY());
});
root.getChildren().add(line);
Scene scene = new Scene(root, 800, 400);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
If you want the line to be limited in length, you'll have to do the proper calculations of course via the angle.

how can i convert local coordinate of MouseEvent to scene coordinate of MouseEvent? in JAVAFX

sources :
flowLine = new Line();
flowLine.setStrokeWidth(3);
flowLine.setStroke(Color.RED);
flowGroup.getChildren().addAll(flowLine);
targetNodeItem.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mEvent) {
drawPoint = new Point2D(mEvent.getSceneX(), mEvent.getSceneY());
startX = drawPoint.getX();
startY = drawPoint.getY();
}
});
targetNodeItem.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mEvent) {
flowLine.setStartX(startX);
flowLine.setStartY(startY);
flowLine.setEndX(mEvent.getSceneX());
flowLine.setEndY(mEvent.getSceneY());
}
});
targetNodeItem is the node.
I want to drag from that node and generate FlowLine, but the coordinates of FlowLine which is generated as an image(http://2url.kr/2lfjlsfa) are incorrect.
==================================================================================
check this out ->>> http://youtu.be/iZOL0Fs-umk
help me please
Your code worked for me to draw a line without coordinate issues...
I used:
public class MouseDrag extends Application
{
private Point2D drawPoint;
private double startX;
private double startY;
#Override
public void start(Stage primaryStage) throws Exception
{
Pane root = new Pane();
Scene scene = new Scene(root, 200, 200);
Group flowGroup = new Group();
final Line line = new Line();
line.setStrokeWidth(3);
line.setStroke(Color.RED);
Label nodeOne = new Label("One");
nodeOne.setOnMousePressed((event) ->
{
drawPoint = new Point2D(event.getSceneX(), event.getSceneY());
startX = drawPoint.getX();
startY = drawPoint.getY();
line.setStartX(startX);
line.setStartY(startY);
});
nodeOne.setOnMouseDragged((event) ->
{
line.setEndX(event.getSceneX());
line.setEndY(event.getSceneY());
System.out.println("X/Y: " + event.getSceneX() + "/" + event.getSceneY());
});
Label nodeTwo = new Label("Two");
nodeTwo.setLayoutX(100);
nodeTwo.setLayoutY(100);
flowGroup.getChildren().addAll(nodeOne, nodeTwo, line);
root.getChildren().addAll(flowGroup);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
JavaFX 8 MouseEvent API
Note that there are multiple X and Y values you can extract from a MouseEvent. In this case, you're using getSceneX() and getSceneY() which gives you coordinates relative to the containing Scene.
Also: "MouseDragged" gets called many times, which creates lots of unnecessary calls to setStartX(...) + setStartY(...). Consider moving it to "MousePressed", which only gets called once (see below). HTH
targetNodeItem.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mEvent) {
flowLine.setStartX(mEvent.getX());
flowLine.setStartY(mEvent.getY());
}
});
targetNodeItem.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mEvent) {
//System.out.println("X: " + mEvent.getX() + " Y: " + mEvent.getY());
flowLine.setEndX(mEvent.getX());
flowLine.setEndY(mEvent.getY());
}
});

Resources