【问题标题】:Frost Glass Effect with dynamic Background JavaFX具有动态背景 JavaFX 的霜玻璃效果
【发布时间】:2015-12-10 20:11:16
【问题描述】:

我正在开发 JavaFX 应用程序:

在这里,我希望左窗格具有模糊背景效果,即当用户滚动地图时,左窗格后面的内容会发生变化,并且我想使用该内容(模糊)作为背景的左窗格。 & 我几乎完成了。

当我滚动地图时,它确实可以工作,并且后面的内容会更新,但在系统监视器中,我可以看到 CPU 使用率、温度和整体电源使用率急剧上升。

为了实现霜玻璃效果,我在 webEngine(包含地图)中添加了一个事件监听器(用于检测鼠标移动):

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

监听器执行一个方法:

  1. 检索左窗格(地图)下方的实际内容。

  2. 图像模糊。

  3. 更新屏幕

要更新屏幕,该方法会删除左窗格(VBox)和上一个图像(即背景)。 & 然后再次首先添加模糊图像窗格,然后将左窗格添加到根窗格。

所以,我认为我遇到性能问题的原因是,当用户拖动地图时,它必须非常快速地删除和添加窗格(左窗格和背景图像)到根窗格。

问题:CPU 使用率非常高

那么,JavaFX 中是否还有其他方法不需要如此高的 CPU 使用率?

类似的东西,不需要一直删除和添加窗格。

【问题讨论】:

  • 您是否尝试过设置左窗格的不透明度?
  • 是的,这是透明效果,但我需要模糊效果。

标签: javafx cpu blur effect panes


【解决方案1】:

在 HBox 中创建两个窗格,将地图相关部分的视图呈现到每个窗格中。在左窗格上设置模糊效果。不需要侦听器、快照或动态添加或删除窗格。

如果需要,请尝试使用不同设置的几种不同模糊效果(有 BoxBlur 和 GuassianBlur),以调整性能特征。

直接在左侧窗格中设置模糊效果,模糊所有内容(按钮文本),并且由于我设置了透明效果,因此此设置仅模糊左侧窗格,

对左侧窗格使用堆栈窗格,左侧地图部分位于堆栈底部(应用模糊效果),透明叠加层位于堆栈顶部(未应用效果)。

有没有办法,我可以模糊窗格的一部分,所以可以选择和模糊位于左侧窗格下方的部分?

是的,您使用的技术类似于:

样本

这是一个快速示例,只是作为概念证明,显然对于您的解决方案,您需要一些稍微不同的东西。

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);
    }
}

【讨论】:

  • 人们可能会补充说,模糊大区域通常是一种代价高昂的效果。因此,我在我的代码中放弃了它。
  • 我相信你建议在地图窗格和左窗格之间插入一个堆栈窗格,并使其透明/半透明,然后对其应用模糊效果,同时使左窗格透明,以便用户可以看到堆栈窗格的模糊效果。但这不起作用,也许它试图模糊堆栈窗格的透明颜色,而不是地图内容的实际颜色
  • 不,我是说将地图一分为二,因此您有两个节点。模糊地图的左侧分割。在 StackPane 中插入地图的左侧拆分和(非模糊)叠加层。请参阅我提供的霜链接中的基于快照的冻结方法,尽管可以在没有快照的情况下完成此操作。
  • 我不喜欢拆分地图,因为每个地图都需要单独的 Web 视图和数据库连接,所以我尝试在左窗格和地图 (webView) 之间放置一个窗格,并且然后继续更新此窗格中的图像并将其模糊,因为我无法为我的应用程序移植 freeze 方法。感谢您的帮助
  • 没关系,有很多方法可以做到这一点,例如将地图拆分为左侧模糊的两个地图节点,或对地图进行快照并覆盖模糊图像,或其他一些方法。您可以根据您的问题限制确定适当的方法。
猜你喜欢
  • 2014-03-01
  • 1970-01-01
  • 2014-05-02
  • 2021-11-12
  • 2021-09-05
  • 2012-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多