Joe
Joe

Reputation: 91

Frost Glass Effect with dynamic Background JavaFX

I'm Developing a JavaFX Application :

https://i.sstatic.net/Q24i4.png

In here, I want the Left Pane to have a Blur Background Effect, i.e, when ever the user scrolls the map, the Content Behind the Left Pane Changes, and i want to Use That Content(Blurred), as the Background of the left Pane. & i've almost done it.

Whenever I scroll the Map, it does work, and content Behind gets updated, but In the System Monitor i can see the CPU usage, Temperature and Overall Power Usage Drastically Rises.

To achieve the Frost Glass Effect, I've Added a Event Listener(for detecting mouse move) to the webEngine(Contains the Map) :

Document doc = webEngine.getDocument();
((EventTarget) doc).addEventListener("mousemove", listener, false);

Listener Executes a Method Which :

  1. Retrieves the Actual Content Beneath the Left Pane(Map).

  2. Blur's the Image.

  3. Updates the Screen

To Update the Screen, the Method removes, the Left Pane(VBox) and the Previous Image(Which was The Background). & then again First Add's the Blurred Image Pane and Then the Left Pane to the Root Pane.

So, I think the reason I'm having Performance Issues with this is because, it has to very rapidly remove and Add Panes(Left Pane and Background Image), to the Root Pane, while the user is dragging the Map.

Problem : Very High CPU Usage

So, Is there any other Approach in JavaFX, Wherein it does not require, such high CPU Usage ?

Something Like, which doesn't require removing and Adding Panes all the time.

Upvotes: 3

Views: 4598

Answers (1)

jewelsea
jewelsea

Reputation: 159416

Create two panes in a HBox, render a view of the relevant section of the map into each pane. Set a blur effect on the left pane. No listeners, snapshots or dynamic adding or removing of panes is required.

Try a couple of different blur effects (there is BoxBlur and GuassianBlur) with different settings, if needed, to adjust performance characteristics.

setting the Blur effect directly on the left Pane, blur's everything (Button text), and as i've set Transparency effect, this setup only blur's the left Pane,

Use a stackpane for the left pane with the left map section at the bottom of stack (with the blur effect applied to it) and the transparent overlay at the top of the stack (with no effect applied to it).

Is there a way , i can blur a part of a pane, so the part lying under the left Pane could be selected & blurred?

Yes, you use a technique similar to:

Sample

Here is a quick sample, just as a proof of concept, obviously for your solution you will need something slightly different.

map

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.effect.GaussianBlur;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

/**
 * Constructs a scene with a pannable Map background.
 */
public class FrostedPannableView extends Application {
    private Image backgroundImage;

    private static final double W = 800;
    private static final double H = 600;

    @Override
    public void init() {
        backgroundImage = new Image("http://www.narniaweb.com/wp-content/uploads/2009/08/NarniaMap.jpg");
    }

    @Override
    public void start(Stage stage) {
        stage.setTitle("Drag the mouse to pan the map");
        stage.setResizable(false);

        // make a transparent pale blue overlay with non transparent blue writing on it.
        final Label label = new Label("Map\nof\nNarnia");
        label.setTextAlignment(TextAlignment.CENTER);
        label.setStyle("-fx-text-fill: midnightblue;  -fx-font: bold italic 40 'serif'; -fx-padding: 0 0 20 0;");

        StackPane glass = new StackPane();
        StackPane.setAlignment(label, Pos.BOTTOM_CENTER);
        glass.getChildren().addAll(label);
        glass.setStyle("-fx-background-color: rgba(0, 100, 100, 0.5);");
        glass.setMaxWidth(W * 1/4);
        glass.setMaxHeight(H);
        StackPane.setAlignment(glass, Pos.CENTER_LEFT);

        // construct a partitioned node with left side blurred.
        ImageView leftMap = new ImageView(backgroundImage);
        ImageView rightMap = new ImageView(backgroundImage);

        // wrap the partitioned node in a pannable scroll pane.
        ScrollPane leftScroll = createScrollPane(leftMap);
        Rectangle leftClip = new Rectangle(W * 1/4, H);
        leftScroll.setClip(leftClip);
        leftScroll.setEffect(new GaussianBlur());

        ScrollPane rightScroll = createScrollPane(rightMap);
        Rectangle rightClip = new Rectangle(W * 1/4, 0, W * 3/4, H);
        rightScroll.setClip(rightClip);

        StackPane composite = new StackPane();
        composite.getChildren().setAll(
                leftScroll,
                rightScroll
        );

        StackPane layout = new StackPane(
                composite,
                glass
        );

        // show the scene.
        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();

        // bind the scroll values together and center the scroll contents.
        leftScroll.hvalueProperty().bind(rightScroll.hvalueProperty());
        leftScroll.vvalueProperty().bind(rightScroll.vvalueProperty());
        rightScroll.setHvalue(rightScroll.getHmin() + (rightScroll.getHmax() - rightScroll.getHmin()) / 2);
        rightScroll.setVvalue(rightScroll.getVmin() + (rightScroll.getVmax() - rightScroll.getVmin()) / 2);
    }

    /**
     * @return a ScrollPane which scrolls the node.
     */
    private ScrollPane createScrollPane(Node node) {
        ScrollPane scroll = new ScrollPane();
        scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scroll.setPannable(true);
        scroll.setMinSize(ScrollPane.USE_PREF_SIZE, ScrollPane.USE_PREF_SIZE);
        scroll.setPrefSize(W, H);
        scroll.setMaxSize(ScrollPane.USE_PREF_SIZE, ScrollPane.USE_PREF_SIZE);
        scroll.setContent(node);
        return scroll;
    }

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

Upvotes: 6

Related Questions