I'm using this to make a iOS-themed JavaFX2 (Java7) application with a frosted glass effect. The problem is that this code uses its effect on an ImageView. I'd like it to use its effect on whatever's behind the window, like this:
Is there anyway to do that? I'd also like that small drop-shadow effect you see around the above image.
To be clear, I don't want that slider or anything, just the effect of being able to see through the window and having that slight shadow around the edges. I want to use this iOS7-ish effect instead of aero, though.
This might be important: I'm using a modified version of Undecorator.
The simplest way to set the JavaFX Scene background color or image is by invoking the Scene 's setFill() method, which can accept a color, gradient or image pattern. A more flexible way to set the background of a scene is to set the root node's background, which can accept multiple images and fills.
You can add more rules according to your needs. Copy -fx-background-image: url('image-url'); -fx-background-repeat: no-repeat; -fx-background-size: 500 500; -fx-background-position: center center; We can use inline CSS rules with the help of the setStyle() method on the root node.
A really efficient way to set the background of the JavaFX scene is by using images. These can be set on any Region object, so if you set them on the root node (assuming it’s a Region not a Group ), you can use them as the base layer of your Scene.
JavaFX - Effects. An effect is any action that enhances the appearance of the graphics. In JavaFX, an effect is an algorithm that is applied on nodes to enhance their appearance visually. The effect property of the Node class is used to specify the effect. In JavaFX, you can set various effects to a node such as bloom, blur and glow.
The class named BoxBlur of the package javafx.scene.effect represents the boxblur effect. Just like Box Blur Gaussian is an effect to blur the nodes in JavaFX. The only difference in the Gaussian Blur effect is that a Gaussian convolution kernel is used to produce a blurring effect.
You can adjust the color of an image by applying the color adjust effect to it. This includes the adjustment of the hue, saturation, brightness and contrast on each pixel The class named ColorAdjust of the package javafx.scene.effect represents the color adjust effect.
import javafx.animation.*;
import javafx.application.*;
import javafx.beans.property.*;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.Label;
import javafx.scene.effect.*;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.util.Duration;
public class FrostyTech extends Application {
private static final double BLUR_AMOUNT = 10;
private static final Effect frostEffect =
new BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);
private static final ImageView background = new ImageView();
private static final StackPane layout = new StackPane();
@Override public void start(Stage stage) {
layout.getChildren().setAll(background, createContent());
layout.setStyle("-fx-background-color: null");
Scene scene = new Scene(
layout,
200, 300,
Color.TRANSPARENT
);
Platform.setImplicitExit(false);
scene.setOnMouseClicked(event -> {
if (event.getClickCount() == 2) Platform.exit();
});
makeSmoke(stage);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
background.setImage(copyBackground(stage));
background.setEffect(frostEffect);
makeDraggable(stage, layout);
}
// copy a background node to be frozen over.
private Image copyBackground(Stage stage) {
final int X = (int) stage.getX();
final int Y = (int) stage.getY();
final int W = (int) stage.getWidth();
final int H = (int) stage.getHeight();
try {
java.awt.Robot robot = new java.awt.Robot();
java.awt.image.BufferedImage image = robot.createScreenCapture(new java.awt.Rectangle(X, Y, W, H));
return SwingFXUtils.toFXImage(image, null);
} catch (java.awt.AWTException e) {
System.out.println("The robot of doom strikes!");
e.printStackTrace();
return null;
}
}
// create some content to be displayed on top of the frozen glass panel.
private Label createContent() {
Label label = new Label("Create a new question for drop shadow effects.\n\nDrag to move\n\nDouble click to close");
label.setPadding(new Insets(10));
label.setStyle("-fx-font-size: 15px; -fx-text-fill: green;");
label.setMaxWidth(250);
label.setWrapText(true);
return label;
}
// makes a stage draggable using a given node.
public void makeDraggable(final Stage stage, final Node byNode) {
final Delta dragDelta = new Delta();
byNode.setOnMousePressed(mouseEvent -> {
// record a delta distance for the drag and drop operation.
dragDelta.x = stage.getX() - mouseEvent.getScreenX();
dragDelta.y = stage.getY() - mouseEvent.getScreenY();
byNode.setCursor(Cursor.MOVE);
});
final BooleanProperty inDrag = new SimpleBooleanProperty(false);
byNode.setOnMouseReleased(mouseEvent -> {
byNode.setCursor(Cursor.HAND);
if (inDrag.get()) {
stage.hide();
Timeline pause = new Timeline(new KeyFrame(Duration.millis(50), event -> {
background.setImage(copyBackground(stage));
layout.getChildren().set(
0,
background
);
stage.show();
}));
pause.play();
}
inDrag.set(false);
});
byNode.setOnMouseDragged(mouseEvent -> {
stage.setX(mouseEvent.getScreenX() + dragDelta.x);
stage.setY(mouseEvent.getScreenY() + dragDelta.y);
layout.getChildren().set(
0,
makeSmoke(stage)
);
inDrag.set(true);
});
byNode.setOnMouseEntered(mouseEvent -> {
if (!mouseEvent.isPrimaryButtonDown()) {
byNode.setCursor(Cursor.HAND);
}
});
byNode.setOnMouseExited(mouseEvent -> {
if (!mouseEvent.isPrimaryButtonDown()) {
byNode.setCursor(Cursor.DEFAULT);
}
});
}
private javafx.scene.shape.Rectangle makeSmoke(Stage stage) {
return new javafx.scene.shape.Rectangle(
stage.getWidth(),
stage.getHeight(),
Color.WHITESMOKE.deriveColor(
0, 1, 1, 0.08
)
);
}
/** records relative x and y co-ordinates. */
private static class Delta {
double x, y;
}
public static void main(String[] args) {
launch(args);
}
}
Related Questions
The visual effect that you want for OS dependent window decoration, can only be achieved through the APIs that OS provides. And thus was eliminated by StageStyle.TRANSPARENT
below.
For JavaFX content itself, you can control the visuals of the stage > scene > root pane
hierarchy. Stage and scene do not (and not aimed to) support advanced stylings so were eliminated by setting as transparent below.
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.setStyle("-fx-background-color: null;");
root.setPadding(new Insets(10));
DoubleProperty doubleProperty = new SimpleDoubleProperty(0);
Region region = new Region();
region.styleProperty().bind(Bindings
.concat("-fx-background-radius:20; -fx-background-color: rgba(56, 176, 209, ")
.concat(doubleProperty)
.concat(");"));
region.setEffect(new DropShadow(10, Color.GREY));
Slider slider = new Slider(0, 1, .3);
doubleProperty.bind(slider.valueProperty());
root.getChildren().addAll(region, slider);
primaryStage.initStyle(StageStyle.TRANSPARENT);
Scene scene = new Scene(root, 300, 250);
scene.setFill(Color.TRANSPARENT);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
However the drop shadow effect does not play well with alpha value of the background color. You can observe it by changing the shadow's color to another contrast one.
Output:
To expand on Jewlsea's answer .. And using the above example with JavaFX ONLY ..
While the classes are not public API, it does avoid the AWT stack completely. Here is a non public example :
// copy a background node to be frozen over.
private Image copyBackground(Stage stage) {
final int X = (int) stage.getX();
final int Y = (int) stage.getY();
final int W = (int) stage.getWidth();
final int H = (int) stage.getHeight();
final Screen screen = Screen.getPrimary();
try {
Robot rbt = com.sun.glass.ui.Application.GetApplication().createRobot();
Pixels p = rbt.getScreenCapture(
(int)screen.getBounds().getMinX(),
(int)screen.getBounds().getMinY(),
(int)screen.getBounds().getWidth(),
(int)screen.getBounds().getHeight(),
true
);
WritableImage dskTop = new WritableImage((int)screen.getBounds().getWidth(), (int)screen.getBounds().getHeight());
dskTop.getPixelWriter().setPixels(
(int)screen.getBounds().getMinX(),
(int)screen.getBounds().getMinY(),
(int)screen.getBounds().getWidth(),
(int)screen.getBounds().getHeight(),
PixelFormat.getByteBgraPreInstance(),
p.asByteBuffer(),
(int)(screen.getBounds().getWidth() * 4)
);
WritableImage image = new WritableImage(W,H);
image.getPixelWriter().setPixels(0, 0, W, H, dskTop.getPixelReader(), X, Y);
return image;
} catch (Exception e) {
System.out.println("The robot of doom strikes!");
e.printStackTrace();
return null;
}
}
Results with a small dropshadow added:
DropShadow shdw = new DropShadow();
shdw.setBlurType(BlurType.GAUSSIAN);
shdw.setColor(Color.GAINSBORO);
shdw.setRadius(10);
shdw.setSpread(0.12);
shdw.setHeight(10);
shdw.setWidth(10);
layout.setEffect(shdw);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With