【问题标题】:How can I build map with region selection?如何使用区域选择构建地图?
【发布时间】:2016-02-07 14:47:17
【问题描述】:

我试图构建由区域(状态)组成的地图,当鼠标进入某个区域时,我需要处理它。有许多分别代表每个区域的 png 图像。我混合了我的图像并得到了我想要的,但是我无法处理某些区域
例如:
这是第一个区域 img


这是第二个区域 img


结果我得到:

代码:

@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);
}

在控制台中,我总是得到“区域 2”。
请给我一些研究建议。提前致谢!

【问题讨论】:

  • 您是否将两个画布添加到同一位置并希望它们能够知道您的鼠标应该在哪一个上?
  • khelwood,我知道,但是如果我将它添加到不同的位置,如何正确混合这些图像?

标签: java javafx


【解决方案1】:

您可以为此使用ImageViewsetPickOnBounds

示例代码:

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);
    }
}

以后请创建一个MCVE,重点关注完成。没有人愿意为了让你不完整的示例工作而浪费时间。

【讨论】:

  • 很高兴知道这是可行的。我认为确实如此,但不确定。尽管如此,我仍然认为使用多边形是更好的方法,因为您可以在没有质量损失的情况下放大和缩小(如果您愿意)。
  • 罗兰,谢谢您的建议!
  • mipa,顺便说一句,我尝试使用多边形,但将非透明区域转换为多边形需要更多时间(我使用此算法link
【解决方案2】:

在我看来,在这里使用画布不是正确的方法。如果您将您的区域定义为多边形并将它们添加到场景图中,您可以将侦听器附加到每个多边形,然后在鼠标悬停在某个区域上时做出相应的反应。也许这对于图像视图也是可能的,但我从未尝试过图像的透明区域是否也是鼠标透明的,这在这种情况下似乎是必要的。对于我的一个程序,我使用了多边形,它工作得很好。

【讨论】:

  • 我可以制作蒙版不透明的图像部分以获取对象的多边形吗?
  • 将图像转换为路径可能有点棘手......如果图像是 SVG,这会容易得多......而且Path 将比Polygon 更灵活。
  • 有很多软件在做这项工作。只需谷歌搜索“轮廓图像”。实际上,多边形是一条路径,但是尽管路径提供了更多选项,但我不确定您是否可以使用它们。我看到的唯一优点是路径可以有洞,但我不知道你的区域是否有洞。
【解决方案3】:

图像数据可用于确定鼠标光标下像素的颜色。如果像素不是完全透明的,那么光标就在那个区域上。

要检索此信息,您需要使用鼠标移动事件的侦听器。为简单起见,您可以使用附加了侦听器的属性来触发区域进入/离开事件:

以下示例假设您保留对用于名为 image1image2 的区域的图像的引用:

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);
    }
});

也不需要创建多个Canvas来绘制图像。

【讨论】:

  • fabian,谢谢,我试试
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 2016-10-14
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 2011-12-22
相关资源
最近更新 更多