Is there a way to draw a radial gradient from black to transparent over the entire scene of a JavaFX stage? I want to achieve something like this:
Here is a quick answer which uses a StackPane as the scene root to allow addition of an overlay with a radial gradient background varying from black to transparent.
Color.BLACK.deriveColor(0, 1, 1, 0.2)
, to change the amount of highlight and intensity in the effect. import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.effect.BoxBlur;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.stage.Stage;
// java 8
// click on the scene to place a shaded lens effect over the scene.
public class ShadedScene extends Application {
@Override
public void start(Stage stage) {
StackPane layout = new StackPane(
new Label("Click to shade/unshade")
);
layout.setPrefSize(400, 300);
Scene scene = new Scene(layout);
makeShadeable(scene);
stage.setScene(scene);
stage.show();
}
/**
* Applies a lens effect gradient to a scene root node.
* The effect is kind of like a flashlight shining against the wall in the dark.
*
* For the gradient to be applied, the scene's root must be defined and a Pane
* to which the effect can added and removed as a child.
*
* @param scene the scene to have the effect applied.
*/
private void makeShadeable(Scene scene) {
if (scene.getRoot() == null ||
!(scene.getRoot() instanceof Pane)) {
return;
}
Pane shade = new Pane();
RadialGradient shadePaint = new RadialGradient(
0, 0, 0.5, 0.5, 1, true, CycleMethod.NO_CYCLE,
new Stop(1, Color.BLACK),
new Stop(0, Color.TRANSPARENT)
);
shade.setBackground(
new Background(
new BackgroundFill(
shadePaint, null, new Insets(-10)
)
)
);
// blur helps reduce visible banding of the radial gradient.
shade.setEffect(new BoxBlur(5, 5, 3));
Pane root = (Pane) scene.getRoot();
scene.setOnMouseClicked(event -> {
if (root.getChildren().contains(shade)) {
root.getChildren().remove(shade);
} else {
root.getChildren().add(shade);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
There are other ways to accomplish something similar to the desired effect. For example the technique below applies an inner shadow and color adjustment to the root pane directly, so it requires no additional nodes.
private void makeShadeableByInnerShadow(Scene scene) {
InnerShadow shade = new InnerShadow();
shade.setWidth(120);
shade.setHeight(120);
shade.setInput(new ColorAdjust(0, 0, -0.3, 0));
Parent root = scene.getRoot();
scene.setOnMouseClicked(event -> {
if (root.getEffect() == null) {
root.setEffect(shade);
} else {
root.setEffect(null);
}
});
}
Considering your example, you could post this on http://pt.stackoverflow.com. as most of your interface is in Brazilian Portuguese.
The answer is exactly what jewelsea posted. But as I was also answering when I got notified that there was an answer, I posted mine as well.
Test.java
package br;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Test extends Application {
public static Stage thisStage;
@Override
public void start(Stage stage) throws Exception {
thisStage = stage;
Parent root = FXMLLoader.load(getClass().getResource("doc.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
stage.setScene(scene);
stage.setTitle("Happy Client - Overlay");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TestController.java
package br;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
public class TestController implements Initializable{
@FXML Pane mainPane;
@FXML Pane overlayPane;
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
overlayPane.getStyleClass().add("grad");
overlayPane.toFront();
overlayPane.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>(){
@Override
public void handle(MouseEvent arg0) {
overlayPane.toBack();
}
});
}
}
doc.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="br.TestController">
<children>
<Pane fx:id="mainPane" prefHeight="98.0" prefWidth="600.0">
<children>
<TableView layoutX="-2.0" layoutY="99.0" prefHeight="300.0" prefWidth="600.0">
<columns>
<TableColumn prefWidth="75.0" text="Nome" />
<TableColumn prefWidth="75.0" text="RG" />
<TableColumn prefWidth="75.0" text="CPF" />
<TableColumn prefWidth="75.0" text="Idade" />
</columns>
</TableView>
<Label layoutX="162.0" layoutY="41.0" style="-fx-font-size: 32;" text="Informe o cliente" />
<Line endX="500.0" layoutX="100.0" layoutY="98.0" startX="-100.0" />
</children>
</Pane>
<Pane fx:id="overlayPane" opacity="0.8" prefHeight="200.0" prefWidth="200.0" />
</children>
</StackPane>
style.css
.grad{
-fx-padding: 40;
-fx-background-color: radial-gradient(center 50% 50%, radius 140%, rgba(200,200,200,70) 5%,rgba(0,0,0,100) 35%);
}
Note that you will have to use a StackPane and not other such as AnchorPane because if you set the style directly on an AnchorPane the style would not work for your elements above it such as your table, as you may see below:
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