JavaFX, как центрировать узел в ImageView (с setPreserveRation == true)? - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть изменяемый размер 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 в то же положение, что и Image внутри ImageView.Image внутри imageView_wheel продолжает изменять размеры и менять свою позицию, что вполне нормально, но я не знаю, как назначить его размер и позицию для gridPane_overlay.

Я пытаюсь добавить слушателей к различным xСвойства / y и width / height позволили достичь некоторых результатов, но он прекратил работать, когда сцена была развернута до максимума и сохранила совершенно неправильные координаты.

Обновление:

Похоже, getParentInParent.getWidth() и getParentInParent.getHeight() возвращают правильный размер Image внутри WrappedImageView, теперь мне нужно определить его положение и назначить размер и позицию для сетки.

Обновление 2:

На основании комментариев я принял следующее решение:

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

1 Ответ

0 голосов
/ 03 декабря 2018

Я также думаю, что именно то, что @Jai упомянул в комментарии.Вы можете включить событие щелчка мыши на самом изображении, чтобы определить, в какой точке его границ щелкают.И тогда вы можете определить диапазон положения щелчка и выполнить свою логику.

Что-то вроде ...

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