自定义JavaFX控件-“;已指定根值";在场景生成器2.0中

自定义JavaFX控件-“;已指定根值";在场景生成器2.0中,java,javafx,javafx-8,scenebuilder,Java,Javafx,Javafx 8,Scenebuilder,我已经使用一个fxml文件和一个Java类实现了一个自定义控件,类似于中的解释(参见下面的代码)。请注意,fxml根元素是用fx:root定义的,我以编程方式调用setRoot 我已经尝试将该控件包含在应用程序的FXML布局中,应用程序加载良好(并按预期显示该控件) 但是,如果我尝试在Scene Builder 2.0中导入包含控件的jar文件,则该控件不会出现在要导入的组件列表中(与同一jar中的其他一些控件不同)。如果我选择“ShowJAR Analysis Report”,它将显示由jav

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

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

但是,如果我尝试在Scene Builder 2.0中导入包含控件的jar文件,则该控件不会出现在要导入的组件列表中(与同一jar中的其他一些控件不同)。如果我选择“ShowJAR Analysis Report”,它将显示由
javafx.fxml.LoadException:Root值已指定引起的错误

您知道为什么在场景生成器中加载时会出现此错误,即使它在实际应用程序中正确加载

以下是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>

以及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);
    }
}
package customjavafx.scene.control;
导入javafx.beans.property.ObjectProperty;
导入javafx.beans.property.SimpleObject属性;
导入javafx.fxml.fxml;
导入javafx.fxml.fxmloader;
导入javafx.scene.control.Label;
导入javafx.scene.image.image;
导入javafx.scene.image.ImageView;
导入javafx.scene.layout.GridPane;
导入javafx.scene.media.media;
导入java.io.IOException;
导入java.util.Map;
公共类MediaMetadataDisplay扩展了GridPane{
公共MediaMetadataDisplay(){
final FXMLLoader FXMLLoader=新的FXMLLoader(getClass().getResource(“MediaMetadataDisplay.fxml”);
fxmlLoader.setRoot(此);
fxmlLoader.setController(此);
试一试{
fxmloader.load();
}捕获(IOException异常){
抛出新的RuntimeException(异常);
}
addListener((obs,oldVal,newVal)->updateMedia(newVal));
}
private final ObjectProperty media=new SimpleObjectProperty((media)null,“media”);
@FXML私有图像视图coverView;
@FXML私有标签trackName;
@FXML私人品牌艺术家;
@FXML私人标签相册;
@FXML私有标签类型;
@FXML私有标签trackNumber;
公共无效更新媒体(媒体){
//TODO显示更新的元数据
}
公共对象属性mediaProperty(){
返回媒体;
}
公共媒体{
返回mediaProperty().get();
}
公共媒体(最终媒体){
mediaProperty().set(媒体);
}
}
在场景生成器显示的stacktrace中,错误的原因是:

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
原因:javafx.fxml.LoadException:已指定根值。
文件:/Users/guillaumegly/Library/Application%20Support/Scene%20Builder/Library/custom-controls_2.11.jar/customjavafx/scene/control/MediaMetadataDisplay.fxml
位于javafx.fxml.fxmloader.constructLoadException(fxmloader.java:2613)
在javafx.fxml.fxmloader.createElement(fxmloader.java:2771)
在javafx.fxml.fxmloader.processStartElement(fxmloader.java:2720)
在javafx.fxml.fxmloader.loadImpl(fxmloader.java:2527)
在javafx.fxml.fxmloader.loadImpl(fxmloader.java:2441)
在javafx.fxml.fxmloader.load(fxmloader.java:2409)
位于customjavafx.scene.control.MediaMetadataDisplay。(MediaMetadataDisplay.java:26)
... 还有18个
删除该行

fxmlLoader.setRoot(this);
您的FXML将根定义为AnchorPane(并且您不能将根设置两次,这就是为什么会出现错误)


我真的很感谢这个帖子


我一直在关注文档中的Javafx FXML教程,而我被困在自定义组件部分。我的问题是,当我调用setRoot方法时,它会抛出一个“Root ready specified”错误。就我个人而言,我通过将root标记添加到定制组件FXML文档中来解决这个问题。它现在起作用了


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

在粗略查看时,您的代码看起来不错,所以我不确定为什么它不起作用(尽管我没有尝试将其与SceneBuilder一起使用)。也许回顾一下Rob Terp的博客可以提供一些见解。此外,你可以将你的问题交叉张贴到;我相信SceneBuilder开发人员有时会监控这些论坛。我也看过那个教程,除了扩展不同的布局(AnchorPane和GridPane)之外,它对我来说似乎没有什么不同。我已经按照你的建议在Oracle论坛上发布了我的问题,我们将看看它是如何进行的。如果我删除
setRoot
,那么它如何知道将组件附加到哪里?Fx:root标记将为你设置root。它基本上是javafx。Fxml文件我不知怎的遇到了相反的问题(当使用

<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">