Border-Radius and Shadow on ImageView


Question

I want to apply a border-radius and a shadow in JavaFX.

In CSS3 it would be:

box-shadow: rgba(0,0,0,0.8) 0 0 10px;
border-radius: 3px;

Now I want this in JavaFX, but even the border-radius is not working in the JavaFX Scene Builder. Here is a screenshot of my problem:

JavaFX Screenshot http://rapid-img.de/images/b92e2112.jpg

On the screenshot you can see that I use:

-fx-border-radius: 10 10 10 10;
-fx-background-radius: 10 10 10 10;
1
19
12/10/2013 9:22:37 AM

Accepted Answer

Use the following css to get a drop shadow:

-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);

See the JavaFX CSS Reference guide for details.

To get the border in addition to the drop shadow, place your ImageView containing your Image in a StackPane. And apply the effect css above to the StackPane, in addition to a background and padding on the StackPane.

For example the css below applied to the StackPane containing your ImageView will provide a red border around your image:

-fx-padding: 10;
-fx-background-color: firebrick;

If you want the background defining your border curved at the edges, then use:

-fx-background-radius: 5;

That gets you an image like below where your image is enclosed in a shadowed border:

batmanlost

If you want to actually round the image itself, it's a bit trickier. You need to apply some code to:

  1. Clip the image to a rounded rectangle.
  2. Snapshot the clipped image.
  3. Store the snapshot image back in the ImageView.
  4. Remove the clip from the ImageView.
  5. Apply the drop shadow effect to the ImageView.

Then you can get something like below:

whereisbatman

Some code for that "BatmanLost.java":

import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

import java.io.IOException;

public class BatmanLost extends Application {

    class WingClipper {
        @FXML
        private ImageView imageView;

        @FXML
        public void initialize() {
            // set a clip to apply rounded border to the original image.
            Rectangle clip = new Rectangle(
                imageView.getFitWidth(), imageView.getFitHeight()
            );
            clip.setArcWidth(20);
            clip.setArcHeight(20);
            imageView.setClip(clip);

            // snapshot the rounded image.
            SnapshotParameters parameters = new SnapshotParameters();
            parameters.setFill(Color.TRANSPARENT);
            WritableImage image = imageView.snapshot(parameters, null);

            // remove the rounding clip so that our effect can show through.
            imageView.setClip(null);

            // apply a shadow effect.
            imageView.setEffect(new DropShadow(20, Color.BLACK));

            // store the rounded image in the imageView.
            imageView.setImage(image);
        }
    }

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

    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader loader = new FXMLLoader(
            getClass().getResource(
                "batmanlostinthemix.fxml"
            )
        );
        loader.setController(new WingClipper());

        Pane batman = loader.load();

        stage.setTitle("Where's Batman?");
        stage.setScene(new Scene(batman));
        stage.show();
    }
}

With some FXML "batmanlostinthemix.fxml":

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="313.0" prefWidth="477.0" style="-fx-background-color: azure;" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
  <children>
    <ImageView fx:id="imageView" layoutX="29.0" layoutY="44.0" fitHeight="224.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true">
      <image>
        <Image url="http://collider.com/wp-content/uploads/lego-batman-movie-dc-super-heroes-unite-1.jpg" />
      </image>
    </ImageView>
  </children>
</AnchorPane>
46
12/10/2013 10:56:13 AM

If you use the answer that jewelsea provided, then make sure to test first whether or not clipping is supported:

Platform.isSupported(ConditionalFeature.SHAPE_CLIP)

I try to avoid conditional features unless I have to use them. In my case, I wanted to make a picture round. So an alternative would be to use a Circle instead of an ImageView:

Circle circle = new Circle(14);
ImagePattern pattern = new ImagePattern(myImage);
circle.setFill(pattern);

The circle can be enhanced to use a shadow if supported:

if (Platform.isSupported(ConditionalFeature.EFFECT)) {
    circle.setEffect(new DropShadow(8, Color.rgb(0, 0, 0, 0.8)));
}

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon