Как создать прозрачную сцену JavaFX с тенями только на границе?

Я прочитал много вопросов о прозрачности и тенях, но не думаю, что видел эту конкретную проблему.

Я могу успешно создать окно с прозрачностью и тенью, но не могу понять, как заставить цветную тень не влиять на цвет прозрачности.

Например, следующий код создает окно с серой прозрачностью и красной тенью. Тем не менее, красный цвет также влияет на прозрачность главного окна, но я хочу, чтобы тень выходила за границы окон.

Итак, что я получаю:

Но то, что я хочу, это: (отредактированное вручную изображение)

Есть идеи, как это сделать?

Мой тестовый код:

@Override
public void start(Stage stage) throws Exception {
    stage.initStyle(StageStyle.TRANSPARENT);

    StackPane stackPane = new StackPane();

    stackPane.setStyle(
        "-fx-background-color: rgba(255, 255, 255, 0.5);" +
        "-fx-effect: dropshadow(gaussian, red, 50, 0, 0, 0);" +
        "-fx-background-insets: 50;"
    );

    Scene scene = new Scene(stackPane, 450, 450);
    scene.setFill(Color.TRANSPARENT);

    stage.setScene(scene);

    stage.show();
}

1 ответ

Решение

Некоторое время мне было любопытно узнать, как добиться такого эффекта тени, когда эффект тени не виден сквозь полупрозрачный верхний контент.

Решение, которое я придумал, состояло в том, чтобы использовать обрезку тени, чтобы она отображалась только за пределами полупрозрачного содержимого, которое она затеняет.

bloodstage

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.*;
import org.scenicview.ScenicView;

// Java 8 code
public class ClippedShadow extends Application {

    private static final int shadowSize = 50;

    @Override public void start(final Stage stage) {
        stage.initStyle(StageStyle.TRANSPARENT);

        StackPane stackPane = new StackPane(createShadowPane());
        stackPane.setStyle(
                "-fx-background-color: rgba(255, 255, 255, 0.5);" +
                "-fx-background-insets: " + shadowSize + ";"
        );

        Scene scene = new Scene(stackPane, 450, 450);
        scene.setFill(Color.TRANSPARENT);
        stage.setScene(scene);
        stage.show();
    }

    // Create a shadow effect as a halo around the pane and not within
    // the pane's content area.
    private Pane createShadowPane() {
        Pane shadowPane = new Pane();
        // a "real" app would do this in a CSS stylesheet.
        shadowPane.setStyle(
                "-fx-background-color: white;" +
                "-fx-effect: dropshadow(gaussian, red, " + shadowSize + ", 0, 0, 0);" +
                "-fx-background-insets: " + shadowSize + ";"
        );

        Rectangle innerRect = new Rectangle();
        Rectangle outerRect = new Rectangle();
        shadowPane.layoutBoundsProperty().addListener(
                (observable, oldBounds, newBounds) -> {
                    innerRect.relocate(
                            newBounds.getMinX() + shadowSize,
                            newBounds.getMinY() + shadowSize
                    );
                    innerRect.setWidth(newBounds.getWidth() - shadowSize * 2);
                    innerRect.setHeight(newBounds.getHeight() - shadowSize * 2);

                    outerRect.setWidth(newBounds.getWidth());
                    outerRect.setHeight(newBounds.getHeight());

                    Shape clip = Shape.subtract(outerRect, innerRect);
                    shadowPane.setClip(clip);
                }
        );

        return shadowPane;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

связанные с

Этот ответ является своего рода продолжением некоторых других вопросов по полупрозрачным окнам и панелям, состоящим из нескольких частей, одну из которых я не удосужился реализовать: как получить эффект тени от ореола на полупрозрачном окне? (этот вопрос)

Другие вопросы по тегам