JavaFX 如何将节点居中到 ImageView(使用 setPreserveRation == true)?

JavaFX how to center a Node to ImageView (with setPreserveRation == true)?

我有一个 resizable ImageView 图像的某些部分应该可以点击。 我的想法是创建一个 GridPane 作为覆盖层并在其中放置几个​​透明按钮,这样当用户单击图像的某些部分时,他实际上会触发图像上的隐藏按钮:

<!-- parent that resizes from time to time -->
<StackPane>

    <StackPane>

        <!-- background image, preserves ration -->
        <ImageView/>

        <!-- overlay with transparent buttons -->
        <!-- should be positionion exactly the same as Image inside ImageView -->
        <GridPane>
            <!- buttons here, columns == rows -->
        </GridPane>

    </StackPane>

</StackPane>

代码如下所示:

    StackPane stackPane_wrapper = new StackPane();
    stackPane_wrapper.setAlignment(Pos.CENTER);

    //menu wheel
    WrappedImageView imageView_wheel = new WrappedImageView();
    imageView_wheel.setImage(new Image("images/menu-wheel.png"));
    imageView_wheel.setPreserveRatio(true);
    stackPane_wrapper.getChildren().add(imageView_wheel);

    GridPane gridPane_overlay = new GridPane();
    stackPane_wrapper.getChildren().add(gridPane_overlay);

    int size = 20;

    for (int i = 0; i < size; ++i)
    {
        ColumnConstraints columnConstraints = new ColumnConstraints();
        columnConstraints.setPercentWidth(100.0d / size);
        gridPane_overlay.getColumnConstraints().add(columnConstraints);

        RowConstraints rowConstraints = new RowConstraints();
        rowConstraints.setPercentHeight(100.0d / size);
        gridPane_overlay.getRowConstraints().add(rowConstraints);
    }

    Button button = new Button();
    button.setText("test");
    //... set style to make this button transparent
    gridPane_overlay.add(button, 3, 5, 2, 4);

我的问题是我无法将 gridPane_overlay 放在与 ImageView 内的 Image 相同的位置。 Image inside imageView_wheel 不断调整大小并改变它的位置,这完全没问题,但我不知道如何将它的大小和位置分配给 gridPane_overlay.

我已经尝试将侦听器添加到各种 x/y 和 width/height 属性,并且能够取得一些结果,但它在舞台最大化并继续设置完全无效的坐标时停止工作。

更新:

似乎 getParentInParent.getWidth()getParentInParent.getHeight() return WrappedImageViewImage 的正确大小,现在我需要获取它的位置并分配两个大小并定位到网格。

更新二:

根据评论,我制定了以下解决方案;

/**
 *
 * @param bounds bounds of image - result of {@link WrappedImageView#localToScene(Bounds)} from {@link WrappedImageView#getBoundsInLocal()}
 * @param x click X - {@link MouseEvent#getSceneX()} minus {@link Bounds#getMinX()}
 * @param y click Y - {@link MouseEvent#getSceneY()} minus {@link Bounds#getMinY()}
 * @return
 */
private int determineClick(Bounds bounds, double x, double y)
{
    double centerX = bounds.getWidth() / 2;
    double centerY = bounds.getHeight() / 2;

    double angle = Math.toDegrees(Math.atan2(x - centerX, y - centerY));

    Point2D center = new Point2D(centerX, centerY);
    Point2D click = new Point2D(x, y);
    double distance = center.distance(click);

    double diameter = centerX;
    boolean isInner = distance < diameter * 0.6;

    //-90 -> -135
    if (angle <= -90 && angle > -135)
    {
        if (isInner)
        {
            return 10;
        }

        return 0;
    }

    //-135 -> -180/180
    if (angle <= -135 && angle > -180)
    {
        if (isInner)
        {
            return 11;
        }

        return 1;
    }

    //-180/180 -> 135
    if (angle <= 180 && angle > 135)
    {
        if (isInner)
        {
            return 12;
        }

        return 2;
    }

    //135 -> 90
    if (angle <= 135 && angle > 90)
    {
        if (isInner)
        {
            return 13;
        }

        return 3;
    }

    //90 -> 45
    if (angle <= 90 && angle > 45)
    {
        if (isInner)
        {
            return 14;
        }

        return 4;
    }

    //45 -> -0/0
    if (angle <= 45 && angle > 0)
    {
        if (isInner)
        {
            return 15;
        }

        return 5;
    }

    //-0/0 -> -45
    if (angle <= 0 && angle > -45)
    {
        if (isInner)
        {
            return 16;
        }

        return 6;
    }

    //-45 -> -90
    if (angle <= -45 && angle > -90)
    {
        if (isInner)
        {
            return 17;
        }

        return 7;
    }

    throw new RuntimeException("Unable to determine point coordinates");
}

我也在想@Jai 在评论中提到的。您可以在 imageview 本身上包含鼠标单击事件,以确定单击其边界的哪个点。然后你可以确定点击位置的范围并执行你的逻辑。

类似...

imageView_wheel.setOnMouseClicked(e -> {
    Bounds bounds = imageView_wheel.localToScene(imageView_wheel.getBoundsInLocal());
    double x = e.getSceneX()-bounds.getMinX();
    double y = e.getSceneY()-bounds.getMinY();
    System.out.println("Clicked at :: "+x+","+y);
    // Now you know at what point in the image bounds is clicked, compute your logic as per your needs..
});