JavaFX 使 WebView 的行为类似于 VBox 中的 Label

JavaFX Make WebView behave like Label in VBox

我有一个允许用户做笔记的程序。当他们做笔记时,我使用 JavaFX HTML 编辑器,它允许表格、列表等。然后我需要向用户显示这些笔记,而且我只能找到在 HTML 中显示的方法JavaFX 是 WebEngine(不幸的是)。

问题是 WebEngine 在容器内的行为与标签不同,我需要 WebView 的行为与标签一样。

我已经用这个例子简化了我的问题。这是一个 VBox,里面有 1 个组件,一个 Label:

如您所见,标签(红色)在 VBox 容器内占据的垂直空间 space 不超过所需的空间,并且包裹文本,这正是我想要的行为。

如果我现在添加一个 WebView,然后添加第二个标签,结果将变为:

中间的webview(白色)现在尽可能垂直展开,标签不再换行。因此,如果在我的实际程序中我有两个 WebView 堆叠在一起,它们都会争夺 50% 的可用垂直 space,而不是只占用尽可能多的 space,这正是我需要的。

此外,像上一张图​​片那样使用 Label/WebView/Label,如果我像这样缩小 window 的宽度:

还有一个问题是 WebView 开始垂直滚动。这不是我想要的,因为我希望它就像一个标签(根据需要展开以占用尽可能多的 space,并且在任何时候都不再占用)。

我试过将webview的vgrow 属性设置为null和Priority.NEVER,但是好像没有效果。

这是完整的代码。感谢您的帮助。

Main.java

package main;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;

public class Main extends Application {
    
    @Override
    public void start(Stage _primaryStage) {

        // create the view
        VBox vBox = new VBox();
        vBox.setPrefHeight(600);
        vBox.setPrefWidth(600);
        
        String textString = "";
        textString += "It's the end of the world as we know it and I feel fine. ";
        textString += textString;
        textString += textString;
        textString += textString;
        textString += textString;
        
        Label testLabel = new Label(textString);
        testLabel.getStyleClass().add("label");
        testLabel.setWrapText(true);
        vBox.getChildren().add(testLabel);
        
        WebView testWebView = new WebView();
        testWebView.getStyleClass().add("webview");
        testWebView.getEngine().loadContent(textString);
        vBox.getChildren().add(testWebView);
        
        VBox.setVgrow(testWebView, Priority.NEVER);
        
        Label testLabel2 = new Label(textString);
        testLabel2.getStyleClass().add("label");
        testLabel2.setWrapText(true);
        vBox.getChildren().add(testLabel2);
        
        Scene scene = new Scene(vBox);
        scene.getStylesheets().add("/main/styles.css");
        
        _primaryStage.setTitle("Notes Program");
        _primaryStage.setScene(scene);
        _primaryStage.show();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
    
}

styles.css

    .label {
    
        -fx-background-color: 'red';
    }

    .webview {
    
    }

目前(在撰写此答案时),JavaFX 或可用的第 3 方库中不存在针对您的问题的开箱即用、易于实施或适应性强的解决方案。

这不是问题的具体答案,而是建议的方法,可以尝试解决此类问题。

使 WebView 适合其内容

您当前解决问题的方法可以概括为:在可调整大小的 JavaFX 节点中呈现 HTML 内容,其行为类似于标签。

为了获得最直接的帮助,请查看下面 linked 问题的答案中的信息,此处不再详细重复。

这个问题与一个类似的问题有关,该问题提供了一些有关如何解决 WebView 大小调整到其 HTML 页面显示内容的信息,尽管那里的信息目前不是确定的并且对所有情况都有竞争力,所以它不会立即解决您的问题:

建议使用一些 JavaScript 脚本来确定文档的大小,然后在 WebView 节点上设置重新大小约束以使节点适合内容,动态更新大小 link 当内容更改或重新呈现或 WebView 的可用 space 更改时。

常见问题解答

评论中包含的其他和澄清问题的答案。

I was hoping I could accomplish this with JavaFX layouts or stylesheets to avoid scripts.

我认为要实现您最初将 WebView 视为标签的解决方案想法,不可避免地要在 JavaScript 和 JavaFX 中编写一些代码。

  • 内置的 JavaFX 布局面板和 CSS 样式表将不会 足够了。
  • 当前的WebView没有提供合适的 支持与 JavaFX 布局系统一起工作。

如果有人已经编写了代码和脚本来为 WebViewLabel 控件创建行为和外观,那么您可以使用它并仅使用与其他控件类似的 JavaFX APIs 对其进行自定义,但这并不据我所知不存在。

Is there another solution that could support lists and tables

我不认为RichTextFX有这个支持(我没有详细看过,所以我不确定)。

Markdown 将很好地支持列表。它还将支持表,可能映射到 JavaFX 节点中的 GridView,而不是 TableView。但是,如果仅使用不支持图标小部件的纯文本编辑器编辑 Markdown,则创建表格的语法可能对用户来说很难。我建议您在网上搜索基于 JavaFX 的 Markdown 查看器,看看它们是否充分支持您所需的功能。

My concern though is if i have a page with 100 webviews on it, do you see performance issues? User could only intereact with 1 at a time ofcourse, but there would still be 100 of them loaded into memory potentially. If it was Java Swing i could simply load content into labels but I didn't realise JavaFX doesnt have that

这样的设置可能存在性能问题,或者它可能执行正常。

您应该创建一个最小的应用程序来研究和基准测试许多 WebView 节点的性能。

当应用程序中显示第一个 WebView 时,单个 WebView 的初始化速度很慢,可检测到滞后,但这可能只是因为要在 JavaFX 系统第一次显示第一个 WebView 时可能需要 运行很多 运行 时间设置和初始化。

我从未尝试过在一个场景中同时显示多个 WebView 节点。也许内部实现会为此提供良好的性能,但您必须对其进行测试以确保,否则您可能会花费大量精力并对结果感到失望。

我猜想 100 个 WebView 可能是一个上限,如果性能不会在较早的情况下下降很多,或者在此后不久随着它们的增加而下降,我会感到惊讶。

JavaFX 并没有真正设置为同时显示 1000 个节点,而且通常不需要,您只需要显示用户当前可见的内容。如果数据太多并且没有输出设备可以呈现,则没有用户可以立即接收所有数据。

这就是存在像 TableView 和 ListView 这样的虚拟化控件的原因,它们具有在工厂中创建的可重用单元格,用于显示底层数据的交互式视图,而不是为完整的(可能是数千行或数百万行)底层数据呈现显示注释数据。

如果您发现自己处于需要创建数千个节点的情况,通常可以使用像 ListView 这样的单元工厂和虚拟化来更好地解决这个问题。 使用这些工具创建新控件是一个高级主题,很难很好地实现。


以下是您在问题中概述的问题的替代方法列表。这些方法可能不会直接适用于您的应用程序,但可能适用于具有不同应用程序但有类似问题需要解决的人。

替代方法:在 HTML 中做更多,在 JavaFX
中做更少

如果您的多个 WebView 聚集在一起以呈现输出,则只需使用单个 WebView 实例并通过 HTML 和 JavaScript.

管理更多布局

Web 引擎比 JavaFX 更擅长某些布局任务(例如布局 html)。使用最好的工具来完成工作。 JavaFX 包括这两种工具(用于渲染场景图的内部 JavaFX 渲染引擎和用于渲染的内部 Web 引擎 html)。因此,您可以选择一种渲染实现或另一种(或两者的混合),以最适合您正在实现的当前任务为准。

替代方法:使用 RichTextFX

对于一些类似的应用程序,RichTextFX 可能是首选解决方案。

RichTextFX provides a memory-efficient text area for JavaFX that allows the developer to style ranges of text, display custom objects in-line (no more HTMLEditor), and override the default behavior only where necessary without overriding any other part of the behavior.

RichTextFX 可能无法完全支持所有必需的功能,但仍然可以完成许多任务,因此在实施您自己的解决方案之前先研究它的功能,看看它是否适合。

替代方法:使用 Markdown

在这种方法下:

  1. 使用编辑器编辑 Markdown。
  2. 使用查看器查看呈现的 Markdown。

没有必要提供完整的 Markdown 支持,只要对您的应用程序用户非常有用即可。

第三方实现中提供了各种 JavaFX Markdown 编辑器和查看器,您可以在网上搜索这些工具。还有许多基于 HTML 的 Markdown 编辑器和查看器,您可以从 WebView 使用它们。因此,您可以选择集成或修改其中之一,而不是从头开始实施。

对于通用库或实用程序,最好使这两个自定义控件(例如 MarkDownEditor 和 MarkDownView)隐藏它们在 JavaFX 控件皮肤中的实现并公开它们 public API 在 JavaFX 控件子类中。

Markdown 编辑器

对于创建(而不是呈现)Markdown 的编辑器,它可能与查看器不同。

编辑器实现,而不是使用内置的 JavaFX HTML编辑器,它是一个所见即所得(所见即所得)编辑器,生成 HTML 输出,您将提供:

  1. 用于创建降价的纯文本编辑器或
  2. 生成 Markdown 输出的所见即所得编辑器。

对于实现,您可以使用:

  1. 100% JavaFX 解决方案或
  2. HTML 嵌入 WebView Markdown 编辑器解决方案(例如类似于 Whosebug 中用于编辑问题和答案的编辑器)。

基于 JavaFX 的编辑器可以像 TextArea 一样简单,也可以更复杂,具有在 JavaFX 中实现的附加格式支持小部件(再次类似于 Whosebug Markdown 编辑器 JavaScript 实现中提供的编辑工具栏,刚刚实现在 JavaFX 中而不是 HTML).

Markdown 查看器

对于观众,您可以选择:

  1. 100% JavaFX 解决方案或
  2. HTML 嵌入 WebView Markdown 编辑器解决方案(例如类似于 Whosebug 中用于编辑问题和答案的编辑器)。

然而,对于编辑器,使用嵌入 WebView 的 HTML markdown 编辑器可能没问题,对于查看器,如果您想查看,最好使用 100% 的 JavaFX 解决方案许多文档片段并像 Label 控件一样显示和调整它们的大小。

从本质上讲,JavaFX 解决方案类似于名为 MarkDownLabel 的新控件的实现,它会根据 MarkDown 文本输入呈现格式化标签。

如果视图需要呈现大文档,它可以配备滚动、缩放和平移功能,但小文档的简单视图不需要这个。此外,单元格样式工厂样式实现(类似于 ListView)可以允许用于呈现视图的节点被更新和重新用于不同的内容而不是重新创建(为了效率),但这只是性能优化(并且非常棘手)所以可能没有必要。