Drop-shadow in an undecorated Pane
Asked Answered
L

4

8

I'm trying to make my Pane a little bit better, visually, so, what I'm doing is: set my stage UNDECORATED (OK) and (TRYING) to add a drop-shadow effect (NOT OK).

I've found some similar cases, though none work: creating undecorated stage in javafx 2.0 and How to add shadow to window in JavaFX?.

It seems like the drop-shadow just isn't set. I can't understand why.

This is what I have:

public static int showConfirmDialog(Window father, String title, String body, String[]      msgBtn) 
{
    System.out.println("La vai eu");
    AnchorPane ap = createPaneWithButton(2, msgBtn,body);
    
    ap.setEffect(initDropShadow());
    Scene scene = new Scene(ap);
    
    Stage stage = new Stage();
    
    stage.setTitle(title);
    
    scene.setFill(null);
    stage.initStyle(StageStyle.TRANSPARENT);
    
    
    stage.setScene(scene);
    stage.initStyle(StageStyle.UNDECORATED);
    stage.show();
    
    return 1;
}

private static AnchorPane createPaneWithButton(int qtBtn, String[] msgsBtn, String body) {
    AnchorPane ap = createPane();
    HBox laneBtn = new HBox(30);
    VBox vbox = new VBox(20);
    
    BorderPane layout = new BorderPane();
    
    Button btn;
    
    for(int i = 0; i < qtBtn; i++ ){
        btn = new Button();
        btn.setText(msgsBtn[i]);
        
        laneBtn.getChildren().add(btn);
    }
    
    vbox.getChildren().add(new Text(body));
    vbox.getChildren().add(laneBtn);
    
    layout.setCenter(vbox);
    
    ap.getChildren().add(layout);
    
    return ap;
}

private static AnchorPane createPane() {
    AnchorPane ap = new AnchorPane();
    
    ap.setLayoutX(250);
    ap.setLayoutY(50);
    
    return ap;
}
Lorenzen answered 10/7, 2013 at 13:14 Comment(1)
Show us initDropShadow().Dinette
J
12

Prior Example Works for Me

The example code supplied for the answer to How to add shadow to window in JavaFX? works fine for me (drop shadow on the dialog visible) on Java 8b96, Windows 7. When I wrote it for JavaFX 2, it also worked in that environment as well.

I couldn't say exactly what you are missing in your example as you did not provide full executable code.

transparent-dialog

Possible Issue with Your Code

My guess is that you are not insetting the background content so that there is space in the dialog for the shadow to be shown. That is, you are filling up the dialog with content and not leaving room in the dialog around the content for the effect to be displayed. The example below achieves the insetting with the css rule -fx-background-insets: 12;

Updated Sample Code

I copied a modified version of the example code into this answer so that it isn't just contained in an obscure gist link off another answer. The modifications are to just use standard API calls as the builders used in the original answer have been deprecated since the original answer was created.

ModalConfirmExample.java

import javafx.application.Application;
import javafx.beans.value.*;
import javafx.concurrent.Worker;
import javafx.event.*;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.BoxBlur;
import javafx.scene.effect.Effect;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.web.WebView;
import javafx.stage.Modality;
import javafx.stage.*;

/**
 * Application modal dialog with the following properties:
 *   translucent background
 *   drop-shadowed border
 *   non-rectangular shape
 *   blur effect applied to parent when dialog is showing
 *   configurable message text
 *   configurable yes and no event handlers
 */
class ModalDialog extends Stage {
    private static final Effect parentEffect = new BoxBlur();

    private final String messageText;
    private final EventHandler<ActionEvent> yesEventHandler;
    private final EventHandler<ActionEvent> noEventHandler;

    public ModalDialog(
            Stage parent,
            String messageText,
            EventHandler<ActionEvent> yesEventHandler,
            EventHandler<ActionEvent> noEventHandler) {
        super(StageStyle.TRANSPARENT);

        this.messageText = messageText;
        this.yesEventHandler = yesEventHandler;
        this.noEventHandler = noEventHandler;

        // initialize the dialog
        initOwner(parent);
        initParentEffects(parent);
        initModality(Modality.APPLICATION_MODAL);
        setScene(createScene(createLayout()));
    }

    private StackPane createLayout() {
        StackPane layout = new StackPane();
        layout.getChildren().setAll(
                createGlassPane(),
                createContentPane()
        );

        return layout;
    }

    private Pane createGlassPane() {
        final Pane glassPane = new Pane();
        glassPane.getStyleClass().add(
                "modal-dialog-glass"
        );

        return glassPane;
    }

    private Pane createContentPane() {
        final HBox contentPane = new HBox();
        contentPane.getStyleClass().add(
                "modal-dialog-content"
        );
        contentPane.getChildren().setAll(
                new Label(messageText),
                createYesButton(),
                createNoButton()
        );

        return contentPane;
    }

    private Button createYesButton() {
        final Button yesButton = new Button("Yes");
        yesButton.setDefaultButton(true);
        yesButton.setOnAction(yesEventHandler);

        return yesButton;
    }

    private Button createNoButton() {
        final Button noButton = new Button("No");
        noButton.setOnAction(noEventHandler);

        return noButton;
    }

    private Scene createScene(StackPane layout) {
        Scene scene = new Scene(layout, Color.TRANSPARENT);
        scene.getStylesheets().add(
                getClass().getResource(
                        "modal-dialog.css"
                ).toExternalForm()
        );

        return scene;
    }

    private void initParentEffects(final Stage parent) {
        this.showingProperty().addListener(new ChangeListener<Boolean>() {
            @Override public void changed(ObservableValue<? extends Boolean> observableValue, Boolean wasShowing, Boolean isShowing) {
                parent.getScene().getRoot().setEffect(
                        isShowing ? parentEffect : null
                );
            }
        });
    }
}

/**
 * Demonstrates a modal confirm box in JavaFX.
 * Dialog is rendered upon a blurred background.
 * Dialog is translucent.
 */
public class ModalConfirmExample extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage primaryStage) {
        final WebView webView = new WebView();

        final ModalDialog dialog = createWebViewPreferenceDialog(primaryStage, webView);

        // show the preference dialog each time a new page is loaded.
        webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends Worker.State> observableValue, Worker.State state, Worker.State newState) {
                if (newState.equals(Worker.State.SUCCEEDED)) {
                    dialog.show();
                    dialog.toFront();
                }
            }
        });
        webView.getEngine().load("http://docs.oracle.com/javafx/");

        // initialize the stage
        primaryStage.setTitle("Modal Confirm Example");
        primaryStage.setScene(new Scene(webView));
        primaryStage.show();
    }

    private ModalDialog createWebViewPreferenceDialog(final Stage primaryStage, final WebView webView) {
        final EventHandler<ActionEvent> yesEventHandler =
                new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent actionEvent) {
                        System.out.println("Liked: " + webView.getEngine().getTitle());
                        primaryStage.getScene().getRoot().setEffect(null);
                        Stage dialogStage = getTargetStage(actionEvent);
                        dialogStage.close();
                    }
                };

        final EventHandler<ActionEvent> noEventHandler =
                new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent actionEvent) {
                        System.out.println("Disliked: " + webView.getEngine().getTitle());
                        primaryStage.getScene().getRoot().setEffect(null);
                        Stage dialogStage = getTargetStage(actionEvent);
                        dialogStage.close();
                    }
                };

        return new ModalDialog(primaryStage, "Will you like this Page?", yesEventHandler, noEventHandler);
    }

    private Stage getTargetStage(ActionEvent actionEvent) {
        Node target = (Node) actionEvent.getTarget();
        return ((Stage) target.getScene().getWindow());
    }
}

modal-dialog.css

.root {
  -fx-opacity: 0.9;
}

.modal-dialog-glass {
  -fx-effect: dropshadow(three-pass-box, derive(cadetblue, -20%), 10, 0, 4, 4); 
  -fx-background-color: derive(cadetblue, -20%); 
  -fx-background-insets: 12; 
  -fx-background-radius: 6;
}

.modal-dialog-content {
  -fx-padding: 20;
  -fx-spacing: 10;
  -fx-alignment: center;
  -fx-font-size: 20;
  -fx-background-color: linear-gradient(to bottom, derive(cadetblue, 20%), cadetblue);
  -fx-border-color: derive(cadetblue, -20%);
  -fx-border-width: 5;
  -fx-background-insets: 12;
  -fx-border-insets: 10;
  -fx-border-radius: 6;
  -fx-background-radius: 6;
}

Use a Library Instead

Also note that for creating dialogs I highly recommend using the ControlsFX project rather than creating your own dialog system. If ControlsFX lacks features which you require (such as drop shadow support), you can file a feature request for that against the ControlsFX project and link back to this answer if necessary.

Jayme answered 10/7, 2013 at 19:46 Comment(2)
MAN, I FC!*@&#ING LOVE YOU! haha!! I Just added the -fx-background-insets! And it solved the problem! O my gosh.. Just thinking it took my hours... Thanks man!! And may Odin bless you!Lorenzen
@GabrielLopes Yeah I get the same reaction when reading his answers.Belloir
P
6

Simple working example.

First result example Second result example

Here is fxml structure:

AnchorPane(200,200) // pane for space for shadow
    \- AnchorPane(center) // appliction pane
         \- Label // application content

Real screen.fxml:

<AnchorPane fx:id="shadowPane" prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <AnchorPane fx:id="rootPane" layoutX="56.0" layoutY="62.0">
         <children>
            <Label fx:id="someLabel" layoutX="30.0" layoutY="30.0" text="Label" textFill="#f20000" />
         </children>
         <padding>
            <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
         </padding>
      </AnchorPane>
   </children>
</AnchorPane>

Main.java

@Override
public void start(Stage stage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("/sample/screen.fxml"));
    AnchorPane shadowPane = loader.load();
    AnchorPane rootPane = (AnchorPane) shadowPane.lookup("#rootPane");
    rootPane.setStyle("-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.4), 10, 0.5, 0.0, 0.0);" +
                      "-fx-background-color: white;"); // Shadow effect

    Scene scene = new Scene(shadowPane);
    stage.setScene(scene);

    shadowPane.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, null, null))); // Some borders for for clarity

    shadowPane.setStyle("-fx-background-color: transparent;"); // Makes shadowPane transparent
    scene.setFill(Color.TRANSPARENT); // Fill our scene with nothing
    stage.initStyle(StageStyle.TRANSPARENT); // Important one!
    stage.show();
}
Philina answered 28/7, 2015 at 21:12 Comment(1)
I would be good to mention, that -fx-padding should be added to the rootPaneFyn
C
1

Well, I found a very simple solution. Maybe this was not supported in earlier versions? However.. The code:

iconPane.setEffect(new DropShadow(2d, 0d, +2d, Color.BLACK));

The picture shows the result - my intention was to show a icon in the look of a FAB

enter image description here

Corrinacorrine answered 14/5, 2015 at 0:2 Comment(0)
D
0

Stage dropshadow without FXML:

public void start(Stage stage){
    final double RADIUS = 5;
    VBox rootNode = new VBox();
    Insets bgInsets = new Insets(RADIUS);
    BackgroundFill bgFill = new BackgroundFill(Color.PINK, null, bgInsets);
    rootNode.setBackground(new Background(bgFill));
    DropShadow dropShadow = new DropShadow(RADIUS, Color.GRAY);
    rootNode.setEffect(dropShadow);

    Scene scene = new Scene(rootNode);
    scene.setFill(Color.TRANSPARENT);
    stage.setScene(scene);
    stage.initStyle(StageStyle.TRANSPARENT);
    stage.show();
}
Doityourself answered 9/12, 2019 at 15:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.