我正在尝试为多种屏幕分辨率(也是高分辨率)创建一个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>
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;
}
}
答案 0 :(得分: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.");
}
双向绑定也是不可能的:
if (isBidirectionalBindingExpression(value)) {
throw constructLoadException(new UnsupportedOperationException("This feature is not currently enabled."));
}
如果你看docs:
表示静态属性的属性与静态属性元素的处理方式类似,并使用类似的语法。 除了更简洁的静态属性属性(如实例属性属性,支持位置,资源和变量解析运算符)之外,唯一的限制是无法创建绑定到静态属性的表达式。
你需要找到另一种方式......
修改强>
基于提供的FXML,我建议的一种避免静态属性的方法是使用HBox
和VBox
,通过绑定使用所需的min / pref / max大小,包装控件。 / p>
这样的事情:
<?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>
答案 1 :(得分:1)
您指出的主要信息是,无法在静态属性中使用表达式,并且永远不会使用变量。
表达式用$ {}编写,必须绑定到属性,“变量”只用$ var写入,并通过getter访问。
我结束了这个可怕的解决方法:AnchorPane.leftAnchor="$dpi.value200"
在Scaling类中实现尽可能多的方法:
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.*/
}
另外,变量分析中存在一种错误,不要将其称为“200Value”(或者像我所说的那样称为“200dp”)。如果变量以数字字符开头,它将停止评估。