自定义 JavaFX 控件 - Scene Builder 2.0 中的“已指定根值”
Posted
技术标签:
【中文标题】自定义 JavaFX 控件 - Scene Builder 2.0 中的“已指定根值”【英文标题】:Custom JavaFX control - "root value already specified" in Scene Builder 2.0 【发布时间】:2014-11-02 05:43:48 【问题描述】:我已经实现了一个自定义控件,使用一个 fxml 文件和一个 Java 类,类似于this official tutorial 中解释的内容(参见下面的代码)。请注意,fxml 根元素是用fx:root
定义的,我以编程方式调用setRoot
。
我已尝试将控件包含在应用程序的 FXML 布局中,并且应用程序加载正常(并按预期显示控件)。
但是,如果我尝试在 Scene Builder 2.0 中导入包含我的控件的 jar 文件,该控件不会出现在要导入的组件列表中(与同一个 jar 中的某些其他控件不同)。如果我选择“显示 JAR 分析报告”,则会显示由javafx.fxml.LoadException: Root value already specified
引起的错误。
您知道为什么在 Scene Builder 中加载时出现此错误,即使它在实际应用程序中正确加载?
这是 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);
错误原因,在 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
【问题讨论】:
粗略查看后,您的代码看起来不错,所以我不确定为什么它不起作用(尽管我没有尝试将它与 SceneBuilder 一起使用)。也许在importing custom controls in SceneBuilder 上查看 Rob Terp 的博客可能会提供一些见解。此外,您可以将您的问题交叉发布到Oracle JavaFX forums;我相信 SceneBuilder 开发人员有时会监控这些论坛。 我也看过那个教程,除了扩展不同的布局(AnchorPane 与 GridPane)之外,它对我来说似乎没有什么不同。我已按照您的建议在 Oracle 论坛上发布了我的问题,我们将看看它是如何进行的。 【参考方案1】:删除线
fxmlLoader.setRoot(this);
您的 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">
非常感谢这篇文章
Root value already specified
【讨论】:
如果我删除setRoot
,那么它怎么知道在哪里附加组件?
Fx:root 标签会为你设置root。它基本上是javafx。 Fxml 文件
我以某种方式遇到了相反的问题(在 .fxml 文件中使用 <fx:root...
语法时),如果我不调用 setRoot()
,我会收到 no root specified
错误。【参考方案2】:
我一直在关注文档中的 Javafx FXML 教程,但我被困在了自定义组件部分。对我来说,问题是当我调用 setRoot 方法时,它会抛出“Root already specified”错误。就个人而言,我通过将根标记添加到自定义组件 FXML 文档中来解决此问题。现在可以了。
我添加这个是为了如果其他人有同样的问题,谷歌可以给他们答案。
【讨论】:
以上是关于自定义 JavaFX 控件 - Scene Builder 2.0 中的“已指定根值”的主要内容,如果未能解决你的问题,请参考以下文章
JavaFx SceneBuilder 2.0 无法解析自定义控件