java 自定义 JavaFX 控件 - Scene Builder 2.0 中的“已指定根值”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25733847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:33:37  来源:igfitidea点击:

Custom JavaFX control - "root value already specified" in Scene Builder 2.0

javajavafxjavafx-8scenebuilder

提问by Cy?egha

I have implemented a custom control, using an fxml file and a Java class, similar to what is explained in this official tutorial(see the code bellow). Note that the fxml root element is defined with fx:rootand I call setRootprogrammatically.

我已经使用 fxml 文件和 Java 类实现了一个自定义控件,类似于本官方教程中解释的内容(请参阅下面的代码)。请注意,fxml 根元素是用程序定义的fx:root,我以setRoot编程方式调用。

I have tried including the control in the FXML layout of an application, and the application loads fine (and displays the control as expected).

我尝试在应用程序的 FXML 布局中包含控件,并且应用程序加载良好(并按预期显示控件)。

However, if I try to import a jar file containing my control in Scene Builder 2.0, the control doesn't appear in the list of components to import (unlike some other controls in the same jar). If I select "Show JAR Analysis Report", it shows an error caused by javafx.fxml.LoadException: Root value already specified.

但是,如果我尝试在 Scene Builder 2.0 中导入包含我的控件的 jar 文件,则该控件不会出现在要导入的组件列表中(与同一 jar 中的某些其他控件不同)。如果我选择“显示 JAR 分析报告”,它会显示由javafx.fxml.LoadException: Root value already specified.

Do you know why I get this error when loading in Scene Builder, even though it loads correctly in a real application?

您知道为什么在 Scene Builder 中加载时会出现此错误,即使它在实际应用程序中正确加载吗?

Here is the FXML :

这是 FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>

<fx:root type="javafx.scene.layout.GridPane" id="MediaMetadataDisplay" hgap="20.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0"
         prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <columnConstraints>
        <ColumnConstraints fillWidth="false" hgrow="NEVER" maxWidth="-Infinity" minWidth="-Infinity" prefWidth="200.0"/>
        <ColumnConstraints halignment="LEFT" hgrow="ALWAYS"/>
    </columnConstraints>
    <rowConstraints>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="40.0" vgrow="SOMETIMES"/>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="25.0" vgrow="SOMETIMES"/>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="25.0" vgrow="SOMETIMES"/>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="25.0" vgrow="SOMETIMES"/>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="25.0" vgrow="SOMETIMES"/>
        <RowConstraints maxHeight="-Infinity" minHeight="-Infinity" prefHeight="30.0" vgrow="SOMETIMES"/>
    </rowConstraints>
    <children>
        <ImageView id="coverView" fx:id="coverView" fitHeight="200.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" GridPane.rowSpan="7"/>
        <Label id="trackName" fx:id="trackName" maxWidth="1.7976931348623157E308" text="trackName" GridPane.columnIndex="1" GridPane.rowIndex="1">
            <font>
                <Font name="System Bold" size="16.0"/>
            </font>
        </Label>
        <Label id="artist" fx:id="artist" maxWidth="1.7976931348623157E308" text="artist" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
        <Label id="album" fx:id="album" maxWidth="1.7976931348623157E308" text="album" GridPane.columnIndex="1" GridPane.rowIndex="3"/>
        <Label id="genre" fx:id="genre" maxWidth="1.7976931348623157E308" text="genre" GridPane.columnIndex="1" GridPane.rowIndex="4"/>
        <Label id="trackNumber" fx:id="trackNumber" maxWidth="1.7976931348623157E308" text="trackNumber" GridPane.columnIndex="1" GridPane.rowIndex="5"/>
    </children>
</fx:root>

And the Java controller/root element:

和 Java 控制器/根元素:

package customjavafx.scene.control;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.scene.media.Media;

import java.io.IOException;
import java.util.Map;

public class MediaMetadataDisplay extends GridPane {

    public MediaMetadataDisplay() {
        final FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MediaMetadataDisplay.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }

        media.addListener((obs, oldVal, newVal) -> updateMedia(newVal));
    }

    private final ObjectProperty<Media> media = new SimpleObjectProperty<>((Media) null, "media");
    @FXML private ImageView coverView;
    @FXML private Label trackName;
    @FXML private Label artist;
    @FXML private Label album;
    @FXML private Label genre;
    @FXML private Label trackNumber;

    public void updateMedia(Media media) {
        // TODO show updated metadata
    }

    public ObjectProperty<Media> mediaProperty() {
        return media;
    }
    public Media getMedia() {
        return mediaProperty().get();
    }
    public void setMedia(final Media media) {
        mediaProperty().set(media);
    }
}

The cause of the error, in the stacktrace shown by Scene Builder :

错误的原因,在 Scene Builder 显示的堆栈跟踪中:

Caused by: javafx.fxml.LoadException: Root value already specified.
file:/Users/guillaumegaly/Library/Application%20Support/Scene%20Builder/Library/custom-controls_2.11.jar!/customjavafx/scene/control/MediaMetadataDisplay.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2613)
    at javafx.fxml.FXMLLoader.createElement(FXMLLoader.java:2771)
    at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2720)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at customjavafx.scene.control.MediaMetadataDisplay.<init>(MediaMetadataDisplay.java:26)
    ... 18 more

回答by swapyonubuntu

Remove the line

删除该行

fxmlLoader.setRoot(this);

Your FXML defines the root to be an AnchorPane (and you can't set the root twice, which is why you are getting the error).

您的 FXML 将根定义为 AnchorPane(并且您不能将根设置两次,这就是您收到错误的原因)。

<fx:root type="javafx.scene.layout.GridPane" id="MediaMetadataDisplay" hgap="20.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0"
         prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">

I am really thankful to this post

我真的很感谢这篇文章

Root value already specified

已指定根值

回答by Dean Irwin

I was following the Javafx FXML tutorials on the documentation, and I got stuck on the custom components section. The problem for me was that when I called the setRoot method, it would throw a "Root already specified" error. Personally, I fixed this by adding the root tag into the custom component FXML document. It now works.

我一直在关注文档上的 Javafx FXML 教程,但卡在了自定义组件部分。我的问题是,当我调用 setRoot 方法时,它会抛出“Root 已指定”错误。就个人而言,我通过将根标记添加到自定义组件 FXML 文档中来解决此问题。它现在可以工作了。

I'm adding this so that if someone else has the same issue, Google can give them the answer.

我添加这个是为了如果其他人有同样的问题,谷歌可以给他们答案。