JavaFX FXML : Cannot bind to static property

标签 javafx fxml

我正在尝试为多种屏幕分辨率(也是高分辨率)创建一个 JavaFX 应用程序。

我想在我的 FXML 文件(JavaFX 项目)中使用变量/计算。
当我仅在 prefWidth、prefHeight 等中进行计算时,此方法有效。当尝试在(例如) AnchorPane.topAnchor 中进行计算时,它给了我以下错误。

-- exec-maven-plugin:1.2.1:exec (default-cli) @ SecureChat ---
dec 04, 2014 10:13:50 AM securechat.helpers.CustomStage initialize
SEVERE: null
javafx.fxml.LoadException: Cannot bind to static property.
file:/D:/private_java/SecureChat/target/SecureChat-1.0-SNAPSHOT.jar!/fxml/main.fxml:24

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2591)
    at javafx.fxml.FXMLLoader.access$100(FXMLLoader.java:104)
    at javafx.fxml.FXMLLoader$Element.processPropertyAttribute(FXMLLoader.java:291)
    at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:771)
    at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2817)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2526)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2403)
    at securechat.helpers.CustomStage.initialize(CustomStage.java:111)
    at securechat.helpers.CustomStage.<init>(CustomStage.java:104)
    at securechat.MainApp.start(MainApp.java:40)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
    at com.sun.javafx.application.LauncherImpl$$Lambda$51/967161415.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
    at com.sun.javafx.application.PlatformImpl$$Lambda$45/584634336.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
    at com.sun.javafx.application.PlatformImpl$$Lambda$47/1040960283.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
    at com.sun.javafx.application.PlatformImpl$$Lambda$46/501263526.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
    at com.sun.glass.ui.win.WinApplication$$Lambda$37/96639997.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:363)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:303)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(LauncherImpl.java:157)
    at com.sun.javafx.application.LauncherImpl$$Lambda$48/815033865.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Root cannot be null
    at javafx.scene.Scene.<init>(Scene.java:313)
    at javafx.scene.Scene.<init>(Scene.java:181)
    at securechat.helpers.CustomStage.initialize(CustomStage.java:120)
    at securechat.helpers.CustomStage.<init>(CustomStage.java:104)
    at securechat.MainApp.start(MainApp.java:40)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
    at com.sun.javafx.application.LauncherImpl$$Lambda$51/967161415.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
    at com.sun.javafx.application.PlatformImpl$$Lambda$45/584634336.run(Unknown Source)
    at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
    at com.sun.javafx.application.PlatformImpl$$Lambda$47/1040960283.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
    at com.sun.javafx.application.PlatformImpl$$Lambda$46/501263526.run(Unknown Source)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
    at com.sun.glass.ui.win.WinApplication$$Lambda$37/96639997.run(Unknown Source)
    ... 1 more
Exception running application securechat.MainApp
------------------------------------------------------------------------
BUILD FAILURE
------------------------------------------------------------------------
Total time: 9.363s
Finished at: Thu Dec 04 10:13:51 CET 2014
Final Memory: 19M/265M
------------------------------------------------------------------------
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:exec (default-cli) on project SecureChat: Command execution failed. Process exited with an error: 1 (Exit value: 1) -> [Help 1]

To see the full stack trace of the errors, re-run Maven with the -e switch.
Re-run Maven using the -X switch to enable full debug logging.

For more information about the errors and possible solutions, please read the following articles:
[Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

当我删除 Main.fxml 中的 AnchorPane.leftAnchor="${dpi.value*200}"(在最后一个 AnchorPane 中)时,它确实有效。

我正在使用以下代码片段。

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

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import securechat.helpers.Scaling?>

<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="securechat.controllers.MainController">
    <children>
        <fx:define>
            <Scaling fx:id="dpi"></Scaling>
        </fx:define>
        <AnchorPane fx:id="chatsAnchorPane" maxWidth="${dpi.value*200}" minWidth="${dpi.value*200}" prefWidth="${dpi.value*200}" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
            <children>
                <Button fx:id="openNewChatWindowButton" onAction="#openNewChatDialog" text="%button.openNewChatDialog" prefHeight="${dpi.value*40}" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
                <ListView fx:id="chatsListView" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="40.0" />
            </children>
        </AnchorPane>
        <AnchorPane fx:id="chatAnchorPane" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="${dpi.value*200}" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
            <children>
                <ListView fx:id="chatMessagesListView" AnchorPane.bottomAnchor="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
                <TextField fx:id="chatMessageTextField" onAction="#sendChatMessage" promptText="%textfield.chatMessagePrompt" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" prefHeight="${dpi.value*40}"  AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
            </children>
        </AnchorPane>
    </children>
</AnchorPane>

缩放.java
package securechat.helpers;

import java.awt.GraphicsEnvironment;

/**
 *
 */
public final class Scaling {

    public double value;

    public Scaling() {
        value = getDefaultScaling();
    }

    private double getDefaultScaling() {
        int width = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().width;
        return width / 1920;
    }

    public double getValue() {
        return value;
    }

}

最佳答案

经过一些调试,我发现在 FXMLLoader类有几个LinkedList<Attribute>列表。一个 if 例如属性属性,如 prefHeight="400.0" , 一个用于静态属性,如 AnchorPane.bottomAnchor="0.0" .

如果你使用像 prefHeight="400.0" 这样的常规值或绑定(bind)表达式,如 prefWidth="${dpi.value*200}" ,这些情况将在此方法中处理processPropertyAttribute() .

对于绑定(bind),有三个初步检查:

    @SuppressWarnings("unchecked")
    public void processPropertyAttribute(Attribute attribute) throws IOException {
        String value = attribute.value;
        if (isBindingExpression(value)) {
            // Resolve the expression
            Expression expression;

            if (attribute.sourceType != null) {
                throw constructLoadException("Cannot bind to static property.");
            }

            if (!isTyped()) {
                throw constructLoadException("Cannot bind to untyped object.");
            }

            if (this.value instanceof Builder) {
                throw constructLoadException("Cannot bind to builder property.");
            }
            // Evaluate the expression
            ...
       } else {
            processValue(attribute.sourceType, attribute.name, value);
       }

prefWidth="${dpi.value*200}"相反,在 AnchorPane.leftAnchor="${dpi.value*200}" 上通过了这些检查你会发现它有一个sourceType:
attribute.sourceType = (java.lang.Class) class javafx.scene.layout.AnchorPane

所以按照设计,这会发生:
if (attribute.sourceType != null) {
     throw constructLoadException("Cannot bind to static property.");
}

同样不可能双向绑定(bind):
if (isBidirectionalBindingExpression(value)) {
    throw constructLoadException(new UnsupportedOperationException("This feature is not currently enabled."));
}

如果您查看 docs :

Attributes representing static properties are handled similarly to static property elements and use a similar syntax. In addition to being more concise, static property attributes, like instance property attributes, support location, resource, and variable resolution operators, the only limitation being that it is not possible to create an expression binding to a static property.



您将需要找到另一种方法...

编辑

根据提供的 FXML,我建议避免使用静态属性的方法是使用 HBoxVBox ,通过绑定(bind)具有所需的最小/首选/最大尺寸,包装控件。

像这样的东西:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import securechat.helpers.Scaling?>

<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="securechat.controllers.MainController">
    <children>
        <fx:define>
            <Scaling fx:id="dpi"></Scaling>
        </fx:define>
        <HBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"  AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <VBox fx:id="chatsVBox" maxWidth="${dpi.value*200}" minWidth="${dpi.value*200}" prefWidth="${dpi.value*200}" HBox.hgrow="NEVER">
               <children>
                      <Button fx:id="openNewChatWindowButton" onAction="#openNewChatDialog" text="%button.openNewChatDialog" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}" prefHeight="${dpi.value*40}" prefWidth="${dpi.value*200}" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" VBox.vgrow="NEVER" />
                      <ListView fx:id="chatsListView" VBox.vgrow="ALWAYS" />
               </children>
            </VBox>
            <VBox fx:id="chatVBox" HBox.hgrow="ALWAYS">
               <children>
                      <ListView fx:id="chatMessagesListView"  VBox.vgrow="ALWAYS" />
                      <TextField fx:id="chatMessageTextField" onAction="#sendChatMessage" maxHeight="${dpi.value*40}" minHeight="${dpi.value*40}"  prefHeight="${dpi.value*40}" promptText="%textfield.chatMessagePrompt" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" VBox.vgrow="NEVER" />
               </children>
            </VBox>
         </children>
      </HBox>
    </children>
</AnchorPane>

关于JavaFX FXML : Cannot bind to static property,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27290316/

相关文章:

java - 使用 Font Awesome 5 SVG 作为 JavaFX 按钮形状

java - 在 JavaFX 的节点的子列表中查找特定节点

java - 在javafx中自动安装自定义字体

JavaFX 动态添加新的文本字段

java - 如何在 JavaFX 中切换场景

JavaFX:CSS 文件中的未知属性

event-handling - 如何在场景图的节点中监听 WindowEvent.WINDOW_SHOWN?

java - Netbeans 找不到场景生成器

java - 如何使 borderpane 中的右侧节点占据整个右侧

java - 如何在 FXML 控件状态被丢弃之前保存它们?