我正在尝试在FXML中创建一个Spinner<Duration>
对象。我创建了扩展DurationSpinnerValueFactory
的SpinnerValueFactory<Duration>
。我已经为DurationSpinnerValueFactory
定义了一个默认的构造函数,以及一个采用最大允许值的构造函数。构造函数定义如下:
import java.time.Duration;
...
public class DurationSpinnerValueFactory extends SpinnerValueFactory<Duration> {
public DurationSpinnerValueFactory() {
this(null);
}
public DurationSpinnerValueFactory(@NamedArg("max") final Duration max) {
...
}
}
在FXML中,以下各项按预期工作(调用默认构造函数):
...
<?import myNamespace.DurationSpinnerValueFactory?>
...
<Spinner fx:id="mySpinner">
<valueFactory>
<DurationSpinnerValueFactory />
</valueFactory>
</Spinner>
...
但是,当我尝试为
max
属性添加值,从而更改被调用的构造函数时,出现错误。下面说明了FXML的更改:<DurationSpinnerValueFactory max="PT10M" />
我得到的错误是:
javafx.fxml.LoadException:
unknown path:23
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
...
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
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$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: java.lang.IllegalArgumentException: Unable to coerce PT10M to class java.time.Duration.
at com.sun.javafx.fxml.builder.ProxyBuilder.createObjectFromDefaultConstructor(ProxyBuilder.java:340)
at com.sun.javafx.fxml.builder.ProxyBuilder.build(ProxyBuilder.java:223)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:763)
at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2823)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2532)
... 18 more
Caused by: java.lang.IllegalArgumentException: Unable to coerce PT10M to class java.time.Duration.
at com.sun.javafx.fxml.BeanAdapter.coerce(BeanAdapter.java:496)
at com.sun.javafx.fxml.builder.ProxyBuilder$Setter.invoke(ProxyBuilder.java:533)
at com.sun.javafx.fxml.builder.ProxyBuilder.createObjectFromDefaultConstructor(ProxyBuilder.java:338)
... 22 more
我知道我可以将构造函数中
max
的类型更改为String
,然后解析构造函数中的值。但是,我宁愿避免这样做,因为我知道max
的类型应为Duration
。有没有办法让FXMLLoader.load(...)
能够从FXML内部解析Duration
对象? 最佳答案
解
尝试使用“ 10m”代替“ PT10M”作为Duration的字符串表示形式,并始终使用javafx.util.Duration
表示与主要与服务JavaFX GUI的代码相关联的所有持续时间相关类型。
解释性背景信息
您对持续时间类型和格式感到困惑。
您提供的“ PT10M”字符串是以下类型的字符串表示形式:java.time.Duration
但是,在DurationSpinnerValueFactory中使用的Duration可能应该是以下类型:javafx.util.Duration
当您查看FXMLLoader
的代码时,正在尝试在valueOf
上调用静态Duration
函数。例如,对于javafx.util.Duration
:javafx.util.Duration.valueOf
查看该函数的文档时,它指出有效输入应为:
语法为“ [数字] [ms | s | m | h]”。
显然,这不是您所使用的。相反,您使用的是java.time.Duration.parse()
格式。
编写以下语句并运行它会引发异常:
javafx.util.Duration.valueOf("PT10M");
Exception in thread "main" java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at javafx.util.Duration.valueOf(Duration.java:85)
但是,如果您仅按以下方式进行编码,则可以正常执行:
javafx.util.Duration.valueOf("10m");
我认为可以通过某种方式告诉FXMLLoader如何从FXML中的文本解析自定义类型。
是的,您可以执行此操作,尽管该文件尚未正式记录下来,但我自己也没有尝试过。通过查看如何处理javafx.util.Duration,可以提供实现静态valueOf函数的包装类型或java.time.Duration的子类。
作为另一种选择,我认为可以将构建器类与某些类类型相关联,以允许它们在FXMLLoader的上下文中进行解析和解析。我没有研究过构建器类型的解决方案,但是它可能依赖于反射或FXMLLoader中公开的某些API。参见,例如,FXMLLoader APIs that take builder factories as parameters。据我所知,绝对没有关于这种方法如何工作的文档,因此您可能需要依靠检查FXMLLoader代码和JavaFX运行时可能附带的一些示例构建器来支持在内部使用内置JavaFX控件。 FXML。
我对您的建议是更改自定义组件以使其与javafx.util.Duration而不是与java.time.Duration一起使用,这样就不必开始编写其他代码来改进不同的工期类型,而且您也不必结束弄乱了自己和其他任何试图使用该控件的人。