Using BoxShadow is a very common thing in modern UIs, so it might not be suprising that designers defining UIs often also use them heavily.
Unfortunately JavaFX has NO 100% compatible effect and even worse one who is closest (DropShadow) leads to a massive performance hit as shown in this video
On the left hand side is a Node who has a DropShadow-Effect applied to it and you notice that once the effect is applied that the animation isn’t smooth any more. On the right hand side you see a new Node we’ll release with e(fx)clipse 3.7.0 who provides a new BoxShadow-Node (named BoxShadow2).
Beside getting a huge performance win, the BoxShadow-Node uses the same semantics the browser counterpart does so you can port CSS definition to your JavaFX-Application.
For completness here’s the code for this demo video.
package org.eclipse.fx.ui.controls.demo;
import org.eclipse.fx.ui.controls.effects.BoxShadow2;
import javafx.animation.Animation;
import javafx.animation.Animation.Status;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.DropShadow;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;
public class InTheShadow extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
BorderPane p = new BorderPane();
p.setPadding(new Insets(20));
Button shadowMe = new Button("Toggle Shadow");
p.setTop(shadowMe);
Region pane;
if (Boolean.getBoolean("efxclipse-shadow")) {
BoxShadow2 shadow = new BoxShadow2(createComplexUI());
shadow.setShadowVisible(false);
pane = shadow;
} else {
pane = new StackPane(createComplexUI());
}
p.setCenter(pane);
shadowMe.setOnAction(evt -> toggleShadow(pane));
Scene s = new Scene(p, 1200, 800);
primaryStage.setTitle("efxclipse-shadow: " + Boolean.getBoolean("efxclipse-shadow"));
primaryStage.setScene(s);
primaryStage.show();
}
private void toggleShadow(Region pane) {
if (pane instanceof BoxShadow2) {
BoxShadow2 s = (BoxShadow2) pane;
s.setShadowVisible(!s.isShadowVisible());
} else {
if (pane.getEffect() != null) {
pane.setEffect(null);
} else {
DropShadow dropShadow = new DropShadow();
dropShadow.setRadius(5.0);
dropShadow.setOffsetX(3.0);
dropShadow.setOffsetY(3.0);
dropShadow.setColor(Color.color(0.4, 0.5, 0.5));
pane.setEffect(dropShadow);
}
}
}
private Node createComplexUI() {
StackPane pane = new StackPane();
pane.setStyle("-fx-background-color: white");
for (int i = 0; i < 100; i++) {
Button b = new Button("Button " + i);
b.setTranslateX(i % 100);
pane.getChildren().add(b);
}
Button animated = new Button("Animated");
StackPane.setAlignment(animated, Pos.BOTTOM_CENTER);
TranslateTransition t = new TranslateTransition(Duration.millis(1000), animated);
t.setAutoReverse(true);
t.setFromX(-300);
t.setToX(300);
t.setCycleCount(Animation.INDEFINITE);
animated.setOnAction(evt -> {
if (t.getStatus() == Status.RUNNING) {
t.pause();
} else {
t.play();
}
});
pane.getChildren().add(animated);
return pane;
}
}
Pingback: e(fx)clipse 3.7.0 is released | Tomsondev Blog