2014-12-04 93 views
4

我正嘗試爲多個屏幕分辨率(也是高分辨率)創建一個JavaFX應用程序。JavaFX FXML:無法綁定到靜態屬性

我想在我的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> 

Scaling.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; 
    } 

} 

回答

3

一些調試後,我發現,在FXMLLoader類有幾個LinkedList<Attribute>名單。一個用於實例屬性屬性,如prefHeight="400.0",另一個用於靜態屬性屬性,如AnchorPane.bottomAnchor="0.0"

如果您使用像prefHeight="400.0"這樣的常規值或綁定表達式,如prefWidth="${dpi.value*200}",這些情況將以此方法處理processPropertyAttribute()

對於綁定,有三種初步檢查:

@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."); 
} 

Als ·其是不可能的雙向綁定:

if (isBidirectionalBindingExpression(value)) { 
    throw constructLoadException(new UnsupportedOperationException("This feature is not currently enabled.")); 
} 

如果你看一下docs:代表靜態屬性

屬性被類似地處理靜態屬性的元素,並使用類似的語法。 除了更簡潔之外,靜態屬性(如實例屬性)支持位置,資源和變量解析運算符,唯一的限制是無法創建表達式綁定到靜態屬性。

您將需要找到另一種方式...

EDIT

基於所提供,我的一種方法來避免靜電性能建議將使用HBoxVBox,將具有所需最小/ PREF /最大經由綁定的尺寸,纏繞控制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> 
     <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> 
+0

你知道另一種方式..? :) – Tijme 2014-12-04 11:54:35

+0

這取決於你的場景。如果你只是想放置這個窗格有一些限制,你將不得不以其他方式提供它們。例如,將'AnchorPane'封裝在'HBox'中,可以在左邊添加一個大小爲'prefWidth =「$ {dpi.value * 200}」'(同時設置最小和最大值)的窗格/框。 – 2014-12-04 12:39:46

+0

嗯,仍然無法得到它的工作。 – Tijme 2014-12-04 13:02:46

1

,你點它是,它是不可能在一個靜態的屬性使用表達式,也永遠不會,但你可以使用一個變量的主要信息。

表達式用$ {}編寫,必須綁定到一個屬性,「變量」只寫入$ var並通過getter訪問。

我這個可怕的解決方法結束:AnchorPane.leftAnchor="$dpi.value200"

而當你在縮放類需要實現儘可能多的方法:

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; 
    } 

    public double getValue100() { 
     return value*100; 
    } 
    public double getValue200() { 
     return value*200; 
    } 
    public double getValue300() { 
     return value*300; 
    } 
    /* etc.*/ 

}

Additionnaly,有一種錯誤的一變量分析,不要稱之爲「200Value」(或「200dp」,就像我一樣)。如果變量以數字字符開頭,它將停止評估。