私はJavaFXアプリケーションを一緒に投げており、プログラムのバックエンドでリスナーテーブルに匿名クラスを追加して、ラベルのテキストを変更しようとしています. Listener はフェッチするはずのデータを返しますが、匿名クラスによってラベルが変更されると、JavaFX はクラッシュします。
フロントエンド:
public class App extends Application {
...
final BackendElement backendElement = new BackendElement();
...
@Override
public void start(Stage mainStage) {
...
GridPane stageContents = generateGridPane(mainStage);
...
mainStage.setScene(new Scene(stageContents));
mainStage.show();
}
private GridPane getGridPane(final Stage mainStage) {
...
final Label labelToBeUpdated = new Label("");
...
backendElement.addModelChangedListener(new ModelChangedListener() {
@Override
public void modelChanged(ModelChangedEvent ev) {
labelToBeUpdated.setText(ev.getSource()); //<- Causes verbose JFX Exception
}
});
}
ModelChangedListener と ModelChangedEvent は、カスタムメイドのオブザーバー パターンの一部にすぎません。エラーを生成する行を単純な行に置き換えるため、構造は確実に機能します
System.out.println(ev.getSource);
必要なデータを印刷します。
私は、プライベート クラスのラベルを匿名クラスから呼び出すことはできないと考えています。結局、どちらも App クラスのフィールドを final にすることはできません。オブザーバー パターンを失わずにこれを修正する方法はありますか?
完全なスタック トレースは次のとおりです。
Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = Timer-0
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
at javafx.scene.Parent$1.onProposedChange(Parent.java:245)
at com.sun.javafx.collections.VetoableObservableList.setAll(VetoableObservableList.java:90)
at com.sun.javafx.collections.ObservableListWrapper.setAll(ObservableListWrapper.java:314)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:602)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:209)
at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:84)
at javafx.scene.control.Labeled.setText(Labeled.java:135)
at ui.App$12.modelChanged(App.java:349)
at ui.BackendElement$CustomTimerTask.informAllListeners(BackendElement.java:108)
at ui.BackendElement$CustomTimerTask.access$0(BackendElement.java:105)
at ui.BackendElement$CustomTimerTask$1.run(BackendElement.java:87)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)