如何在 FXML 中的对象元素之前创建对对象的引用?

How do I create a reference to an object before the object's element in FXML?

我在 FXML 文档中定义了两个对象。我希望其中之一有一个引用,也用 FXML 定义,到另一个。具有其他对象的对象的 FXML 元素在文档中排在第一位。当通过 javafx.fxml.FXMLLoader 加载时,属性 未分配。如果具有另一个对象的对象排在第二位,它 分配 属性 。有没有办法将对象引用分配给 FXML 文档中较早出现的对象的 属性?

这是一个最小的完整可验证示例。引用另一个对象并且在它没有分配 属性 之前出现的对象,并且在测试时它是空的。它引用的对象之后的那个确实得到了它的 属性 分配并打印出对象的 toString()。

issue.fxml:

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import test.control.*?>

<HBox xmlns:fx="http://javafx.com/fxml/1" id="pane1" prefHeight="400.0" prefWidth="600.0">
    <FriendlyButton fx:id="priorObjectReference" friend="$normalButton" />
    <Button fx:id="normalButton" />
    <FriendlyButton fx:id="subsequentObjectReference" friend="$normalButton" />
</HBox>

FXMLIssue.java,在 FXML 之上加载并尝试打印对象引用:

import java.io.IOException;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import test.control.FriendlyButton;

public class FXMLIssue extends Application {
    @Override
    public void start(Stage stage) {
        Parent container = null;
        try {
            container = FXMLLoader.load(Paths.get("issue.fxml").toUri().toURL());
        } catch (IOException ex) {
            Logger.getLogger(FXMLIssue.class.getName()).log(Level.SEVERE, "Failed to load file.", ex);
            Platform.exit();
        }

        FriendlyButton priorObjectReference = (FriendlyButton) container.lookup("#priorObjectReference");
        System.out.println(priorObjectReference.getFriend() == null ? "priorObjectReference's friend property wasn't loaded from FXML" : "priorObjectReference's friend is: " + priorObjectReference.getFriend().toString());

        FriendlyButton subsequentObjectReference = (FriendlyButton) container.lookup("#subsequentObjectReference");
        System.out.println(subsequentObjectReference.getFriend() == null ? "subsequentObjectReference's friend property wasn't loaded from FXML" : "subsequentObjectReference's friend is: " + subsequentObjectReference.getFriend().toString());

        Platform.exit();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

FriendlyButton.java,只是一个 class 有一个 属性 引用 FXML 中的另一个对象:

package test.control;

import javafx.scene.control.Button;

public class FriendlyButton extends Button {
    private Button mFriend;

    public Button getFriend() {
        return mFriend;
    }

    public void setFriend(Button friend) {
        mFriend = friend;
    }
}
<HBox xmlns:fx="http://javafx.com/fxml/1" id="pane1" prefHeight="400.0" prefWidth="600.0">
    <fx:define>
        <Button fx:id="normalButton" />
    </fx:define>
    <FriendlyButton fx:id="priorObjectReference" friend="$normalButton" />
    <fx:reference source="normalButton" />
    <FriendlyButton fx:id="subsequentObjectReference" friend="$normalButton" />
</HBox>

另一种解决方案是用 JavaFX 属性 重写 FriendlyButton class 并至少使用 expression binding (${}) 作为第一个参考:

<FriendlyButton fx:id="priorObjectReference" friend="${normalButton}" />
<Button fx:id="normalButton"/>
<FriendlyButton fx:id="subsequentObjectReference" friend="$normalButton" />

// FriendlyButton.java:

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Button;

public class FriendlyButton extends Button {
    private ObjectProperty<Button> friend = new SimpleObjectProperty<>();
    public final Button getFriend() { return friend.get(); }
    public final void setFriend(Button value) { friend.set(value); }
    public final ObjectProperty<Button> friendProperty() { return friend; }
}