2016-05-17 6 views
1

Spinner<Duration>オブジェクトをFXML内に作成しようとしています。 SpinnerValueFactory<Duration>を拡張するDurationSpinnerValueFactoryを作成しました。 DurationSpinnerValueFactoryのデフォルトのコンストラクタと、最大許容値をとるコンストラクタを定義しました。次のようにコンストラクタが定義されています。コンストラクタがjava.time.DurationになるカスタムJavaFXコンポーネント

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 

私は内の値を解析し、その後、Stringにコンストラクタでmaxの種類を変えることができることを知っていますコンストラクタしかし、私はmaxのタイプがDurationでなければならないことを知っているので、これを避けることを好むでしょう。 FXMLLoader.load(...)をFXML内のDurationオブジェクトを解析できるようにする方法はありますか?

答えて

1

ソリューション

はあなたの期間の文字列表現としての代わりに「PT10M」の「10メートル」を使用して、一貫サービスを提供するために、主にターゲットを絞ったコードに関連付けられている期間に関連する種類のすべてを表現するためにjavafx.util.Durationを使用してみてくださいJavaFX GUI。

凡例の背景情報

あなたの期間の種類とフォーマットについて混乱してきています。

javafx.util.Duration:しかし、あなたのDurationSpinnerValueFactoryに使用される期間は、おそらく以下の型でなければなりません

java.time.Duration

:あなたが提供

「PT10M」の文字列は、次のタイプの文字列表現であります

FXMLLoaderは、コードを見ると静的なvalueOf関数を呼び出そうとしていますDuration。例えば、javafx.util.Durationのために:|

構文は、「[番号] [msです:

javafx.util.Duration.valueOf

あなたは、その関数のドキュメントを見て、それが有効な入力があるべきと述べています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のコンテキスト内でそれらを解決して解析できるようにすると思います。私はBuilder型のソリューションを検討していませんが、FXMLLoaderに公開されているAPIやリフレクションに依存している可能性があります。例えば、FXMLLoader APIs that take builder factories as parametersを参照されたい。私の知る限りでは、このアプローチがどのように機能するかはまったく書かれていませんので、FXMLLoaderコードと、JavaFXランタイムとともに出荷されるいくつかのサンプルビルダーを調べて、組み込みのJavaFXコントロールの使用をサポートする必要がありますFXML。

カスタムコンポーネントをjava.time.Durationではなくjavafx.util.Durationで使用するように変更することをお勧めします。異なる継続時間タイプをレトロフィットするための追加コードの作成を開始する必要はなく、あなた自身と他の誰かがコントロールを使用しようとしていることを混乱させてしまうことはありません。

+0

私が掲示したコードが与えられている例外は「* PT10Mをクラスjava.time.Duration *に強制することができません」です。したがって、 'FXMLLoader'は、文字列" PT10M "を' java.time.Duration'に強制しようとしています。これは、その形式の文字列を必要とします。 'java.time.Duration'を使用することができない場合は、あなたのソリューションを使用します。しかし、FXMLLoaderにFXML内のテキストからカスタムタイプを解析する方法を伝える方法があると思います。 –

+0

はい、それは私がコミュニケートしようとしていたものです.FXMLLoaderソースの「Unable to coerce」メッセージが見つかります。あなたの完全な例を実行しようとはしませんでした。入力コードを少しだけ複製するのは難しいでしょう。他のエラーがあるかもしれません。 – jewelsea

+0

あなたのソリューションはかなり良い回避策を提供します。私は単に、それぞれのコンストラクタのコンストラクタオーバーロードを追加しました。型 'java.time.Duration'を' javafx.util 'に置き換えました。'Duration'を呼び出し、' javafx.util.Duration'の値を 'java.time.Duration.ofSeconds((long)javafxDuration.toSeconds())'を使って変換することによって、他のコンストラクタに呼び出しを転送します。 –

1

FXMLLoaderコードを指している@ jewelseaのおかげです。コードを確認した後、カスタムパーサーをFXMLロードプロセスに追加する方法がないことが明らかになりました。ただし、不明なタイプTのデフォルトアクションは、反射的に署名public static T valueOf(String value)を持つ静的メソッドを呼び出すことです。したがって、私は単にjava.time.Durationため、次のラッパークラスを作成しました:

public class DurationWrapper { 

    private final Duration myValue; 

    private DurationWrapper(final Duration value) { 
     myValue = value; 
    } 

    public static DurationWrapper valueOf(final String value) { 
     final Duration duration = Duration.parse(value); 
     final DurationWrapper result = new DurationWrapper(duration); 
     return result; 
    } 

    public Duration getValue() { 
     return myValue; 
    } 

} 

その後、私は私のDurationSpinnerValueFactoryコンストラクタを修正:

public class DurationSpinnerValueFactory extends SpinnerValueFactory<Duration> { 

    public DurationSpinnerValueFactory(
      @NamedArg("max") final DurationWrapper max) { 
     this(max.getValue()); 
    } 

    public DurationSpinnerValueFactory(final Duration max) { 
     ... 
    } 

} 

は、私はまだFXMLLoader.load(...)を取るコンストラクタを選択することが保証されていることを確認する必要がありますDurationを受け取るものの、DurationWrapperがありますが、JRE 8u77 x64を実行しているWindows 7 Enterprise SP1 x64で動作しています。そうでない場合は、Durationオブジェクトを非公開にするコンストラクタを作成します。

関連する問題