3

I'm Developing a JavaFX Application :

https://i.stack.imgur.com/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.

Joe
  • 91
  • 1
  • 3
  • 8

1 Answers1

4

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);
    }
}
Community
  • 1
  • 1
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • One might add that blurring large areas is a costy effect in general. I abbandoned it therefore in my code. – mipa Dec 09 '15 at 19:20
  • I believe you're suggesting to Insert a Stack Pane in between the map pane and the left pane, and make it transparent/translucent and then apply the blur effect to it, and also make the left Pane transparent, so that user can see the blur effect of the stack pane. but this didn't work, maybe its trying to blur the Transparent Color of the stack Pane, and not the actual color of the content of the map – Joe Dec 10 '15 at 09:59
  • No, I'm saying to split the map in two, so you have two nodes for it. Blur the left split of the map. Insert both the left split of your map and the (non-blurry) overlay in a StackPane. See the snapshot based freeze method from the frost link I provided, though it is possible to accomplish this without a snapshot. – jewelsea Dec 10 '15 at 10:49
  • I don't prefer to split the map, because each map would need a separate web view & DB Connection, so i tried placing a pane in between the left pane and the map(webView), and then just keep updating the image in this pane and blurring it, because i'm not able to port the freeze method for my app. Thank you for your help – Joe Dec 10 '15 at 11:58
  • That's fine, there are numerous ways to accomplish this, e.g. split the map into two map nodes with the left blurred, or snapshot the map and overlay a blurred image, or some other method. You can determine the appropriate approach based upon your problem constraints. – jewelsea Dec 10 '15 at 12:00