Reputation: 674
I trying to build map which consist of regions(states) and when mouse entered to some region, I need handle it. Have many png images which represent each region separately. I blend my images and got what I want, but I can't handle some region.
For instance:
It's a first region img
Code:
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("view/MapView.fxml"));
Pane root = loader.load();
primaryStage.setTitle("Map");
primaryStage.setScene(new Scene(root, 700, 700));
primaryStage.show();
//First region
File file = new File("src/res/img/region1.png");
Canvas canvas = new Canvas(700, 700);
canvas.addEventHandler(MouseEvent.MOUSE_ENTERED_TARGET, event -> System.out.println("Region 1"));
GraphicsContext graphicsContext = canvas.getGraphicsContext2D();
graphicsContext.drawImage(new Image(file.toURI().toString()), 0, 0);
root.getChildren().add(canvas);
//Second region
file = new File("src/res/img/region2.png");
canvas = new Canvas(700, 700);
canvas.addEventHandler(MouseEvent.MOUSE_ENTERED_TARGET, event -> System.out.println("Region 2"));
graphicsContext = canvas.getGraphicsContext2D();
graphicsContext.drawImage(new Image(file.toURI().toString()), 0, 0);
root.getChildren().add(canvas);
}
In console I got always "Region 2".
Please give me tips for research. Thanks in advance!
Upvotes: 1
Views: 336
Reputation: 18415
You can use an ImageView and setPickOnBounds for that.
Example code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class LayersWithMouseEvents extends Application {
@Override
public void start(Stage primaryStage) {
// root
StackPane root = new StackPane();
// create layers
Pane region1Layer = new Pane();
Pane region2Layer = new Pane();
// add layers
root.getChildren().addAll(region1Layer, region2Layer);
// load images
ImageView region1ImageView = new ImageView( new Image( getClass().getResource("region1.png").toExternalForm()));
ImageView region2ImageView = new ImageView( new Image( getClass().getResource("region2.png").toExternalForm()));
// add images
region1Layer.getChildren().add(region1ImageView);
region2Layer.getChildren().add(region2ImageView);
// mouse handler
region1Layer.setOnMousePressed(e -> System.out.println("Region 1: " + e));
region2Layer.setOnMousePressed(e -> System.out.println("Region 2: " + e));
// this is the magic that allows you to click on the separate layers, but ONLY(!) as long as the layer is transparent
region1Layer.setPickOnBounds(false);
region2Layer.setPickOnBounds(false);
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In the future please create an MCVE with focus on complete. Nobody wants to waste their time in order to make your incomplete example work.
Upvotes: 3
Reputation: 82461
The image data can be used to determine the color of the pixels under the mouse cursor. If the pixel is not fully transparent, then the cursor is on that region.
To retrieve this information you need to use a listener for the mouse moved event. For simplicity you can use a property with a listener attached to trigger the region enter/leave events:
The following example assumes you keep references to the images used for the regions named image1
and image2
:
PixelReader reader1 = image1.getPixelReader();
PixelReader reader2 = image2.getPixelReader();
SimpleIntegerProperty region = new SimpleIntegerProperty(-1);
region.addListener((observable, oldValue, newValue) -> {
if (newValue.intValue() < 0) {
System.out.println("region left");
} else {
System.out.println("Region " + (newValue.intValue() + 1));
}
});
canvas.setOnMouseMoved(event -> {
int x = (int) event.getX();
int y = (int) event.getY();
if (x < image1.getWidth() && y < image1.getHeight() && reader1.getColor(x, y).getOpacity() != 0) {
region.set(0);
} else if (x < image2.getWidth() && y < image2.getHeight() && reader2.getColor(x, y).getOpacity() != 0) {
region.set(1);
} else {
region.set(-1);
}
});
Also there is no need to create multiple Canvas
to paint the images.
Upvotes: 2
Reputation: 10650
To my opinion using a canvas here is not the right approach. If you would define your regions as polygons and add them to the scene graph you can attach a listener to each of these polygons and then react accordingly if the mouse is over some region. Maybe this is also possible with image views but I have never tried wether a transparent region of an image is also mouse transparent which seems to be necessary in that case. For a program of mine I used polygons and it works nicely.
Upvotes: 2