javajavafxscenebuilder

SceneBuilder custom Component selection blank


I'm trying to create a custom component in JavaFX and import it to SceneBuilder. I created a project that contains only that custom component, and I want to be able to import that component into SceneBuilder. I expected to see CustomComponent in the SceneBuilder selection. However, the custom component selection in SceneBuilder turned out to be blank! How can I solve that? Note that if I use the example described in JavaFX custom component usage in SceneBuilder, it works perfectly.

I don't have a specific FXML file that I want SceneBuilder to show correctly, I just want to import this custom component (that is named CustomComponent) into SceneBuilder.

Here are all my project files. (Note: The Artifact ID of this project is custom-component)

src/main/java/com/remmymilkyway/customcomponent/CustomComponent.java

package com.remmymilkyway.customcomponent;

import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

import java.net.URL;


public class CustomComponent extends Region {
    private final WebView webView;
    private final WebEngine webEngine;

    public CustomComponent() {
        this.webView = new WebView();
        this.webEngine = webView.getEngine();

        URL url = getClass().getResource("/monaco_editor.html");
        if (url != null) {
            webEngine.load(url.toExternalForm());
        }

        this.getChildren().add(webView);
    }
    public String getEditorContent() {
        return (String) webEngine.executeScript("getEditorValue()");
    }

    public void setEditorContent(String newValue) {
        String escapedContent = newValue.replace("'", "\\'").replace("\n", "\\n");
        webEngine.executeScript("setEditorValue('" + escapedContent + "');");
    }

    public void setFontFamily(String fontFamily) {
        webEngine.executeScript("setFontFamily('" + fontFamily + "');");
    }

    public void setFontSize(int fontSize) {
        webEngine.executeScript("setFontSize(" + fontSize + ");");
    }

    public void setLanguage(String languageIdentifier) {
        webEngine.executeScript("setLanguage('" + languageIdentifier + "');");
    }

    @Override
    protected void layoutChildren() {
        webView.setPrefSize(getWidth(), getHeight());
        webView.resize(getWidth(), getHeight());
    }
}

src/main/java/resources/monaco_editor.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Monaco Editor in JavaFX</title>
    <script src="monaco-editor/min/vs/loader.js"></script>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            width: 100%;
        }
        #container {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div id="container"></div>
<script>
    require.config({ paths: { 'vs': 'monaco-editor/min/vs' }});
    require(['vs/editor/editor.main'], function () {
        var editor = monaco.editor.create(document.getElementById('container'), {
            language: 'cpp',
            automaticLayout: true
        });

        window.getEditorValue = function () {
            return editor.getValue();
        }
        window.setEditorValue = function (newValue) {
            editor.setValue(newValue);
        }

        window.setFontFamily = function(fontFamily) {
            editor.updateOptions({
                fontFamily: fontFamily
            });
        };

        window.setFontSize = function(fontSize) {
            editor.updateOptions({
                fontSize: fontSize
            });
        };

        window.setLanguage = function(language) {
            monaco.editor.setModelLanguage(editor.getModel(), language);
        };
    });
</script>
</body>
</html>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.remmymilkyway</groupId>
    <artifactId>custom-component</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>custom-component</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>5.10.2</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>22.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>22.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-web</artifactId>
            <version>22.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>22</source>
                    <target>22</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <!-- Default configuration for running with: mvn clean javafx:run -->
                        <id>default-cli</id>
                        <configuration>
                            <mainClass>
                                com.remmymilkyway.customcomponent/com.remmymilkyway.customcomponent.HelloApplication
                            </mainClass>
                            <launcher>app</launcher>
                            <jlinkZipName>app</jlinkZipName>
                            <jlinkImageName>app</jlinkImageName>
                            <noManPages>true</noManPages>
                            <stripDebug>true</stripDebug>
                            <noHeaderFiles>true</noHeaderFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

The Monaco Editor distribution files are downloaded in the folder src/main/resources/monaco-editor.

I ran the command mvn install and tried to import the project into SceneBuilder by clicking on the Manually add Library from repository button and imported version 1.0-SNAPSHOT. As shown in this picture:

Screenshot

And I an empty selection when I clicked on the ADD JAR button.

Screenshot of empty selection


Solution

  • SceneBuilder 22 does not support WebView in custom components

    I tried this and was also unable to get imports of components that rely on WebView to work with SceneBuilder 22.

    Even though SceneBuilder will work with the in-built WebView control (it has a component that works with that), it won't work with a custom component that includes a WebView, at least from my testing. You could file a feature request with Gluon to add the support if you wish.

    Test project

    You can use a much simpler case to get it to fail.

    This test project, roughly follows the example at:

    A project with these two components will only see for import the ButtonComponent, not the WebViewComponent.

    src/main/java/com/example/customcomponent/ButtonComponent.java

    package com.example.customcomponent;
    
    import javafx.scene.control.Button;
    import javafx.scene.layout.Pane;
    
    public class ButtonComponent extends Pane {
        public ButtonComponent() {
            super(new Button("Button"));
        }
    }
    

    src/main/java/com/example/customcomponent/WebViewComponent.java

    package com.example.customcomponent;
    
    import javafx.scene.layout.Pane;
    import javafx.scene.web.WebView;
    
    public class WebViewComponent extends Pane {
        public WebViewComponent() {
            super(new WebView());
        }
    }
    

    src/main/java/module-info.java

    module com.example.customcomponent {
        requires javafx.web;
        exports com.example.customcomponent;
    }
    

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example</groupId>
        <artifactId>editor-component</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>editor-component</name>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>22</maven.compiler.source>
            <maven.compiler.target>22</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-web</artifactId>
                <version>22.0.2</version>
            </dependency>
        </dependencies>
    </project>
    

    SceneBuilder 22 import dialog

    Importing into SceneBuilder from the local maven repository (after running a mvn install on the project):

    <groupId>com.example</groupId>
    <artifactId>editor-component</artifactId>
    <version>1.0-SNAPSHOT</version>
    

    Available components:

    no webview component displayed