2017-08-11 11 views
0

私はいくつかの建物を管理するアプリケーションを更新したいと思います。これらのそれぞれは、それに含まれる人の数を身に着けます。 10秒ごとに、各建物の人口は1人増えます。バックグラウンド定期タスクからモデルプロパティを変更するにはどうすればよいですか?

「更新」とは、「SwingからJavaFXへのポート」という意味です。

現在のSwingアプリケーションがバックグラウンドjavax.swing.Timerスレッドとの定期的なアクションを実装:

new Timer(10000, (e) -> { 
    for (Building building : theSuperKawaiBuildingList) { 
     building.setPopulation(building.getPopulation() + 1); 
    } 
}); 

を...とmodel.Buildingjava.util.Observableのサブクラスである:今

public class Building extends Observable { 
    private int population; 

    public synchronized int getPoulation() { 
     return population; 
    } 

    public synchronized void setPoulation(int value) { 
     population = value; 

     setChanged(); 
     notifyObservers(); 
    } 

    public Building(int initPopulation) { 
     population = initPopulation; 
    } 
} 

、私は思いますSwingの代わりにJavaFXを使用し、APIのバインディング機能を使用して新しいGUIを構築したい場合は、model.Buildingクラスを実装することがあります。

public class Building { 
    // <editor-fold desc="FX Property - Population"> 
    private final IntegerProperty population; 
    public IntegerProperty populationProperty() { return population; } 
    public int getPopulation() { return population.get(); } 
    public void setPopulation(int value) { population.set(value); } 
    // </editor-fold> 

    public Building(int initPopulation) { 
     population = new SimpleIntegerProperty(initPopulation); 
    } 
} 

私は、定期的なものについては、法案に合うかもしれないと思うが、読んだ後には、アクティブなシーングラフにバインドされるプロパティを更新する(スレッド)安全性に疑問がある。バックグラウンドタスク...

バインドに私ができることを可能にするいくつかの魔法が付属していない限り、それを実行するのがベストプラクティスです。

+0

コンテキストPS:私はJavaFX初心者ですが、これはこのフレームワークの私の最初のアプリです。 – Odepax

答えて

1

シーングラフ内のUIコンポーネントのプロパティによってバインドされている場合、モデル内のプロパティをバックグラウンドスレッドから更新することはできません。

new Timer(10000, (e) -> { 
    Platform.runLater(() -> { 
     for (Building building : theSuperKawaiBuildingList) { 
      building.setPopulation(building.getPopulation() + 1); 
     } 
    }); 
}); 

(またはjava.util.Timerと同等の操作を行う):

あなたはそれがFXのアプリケーションスレッド上で実行されるように、Platform.runLater(...)でモデルを更新呼び出しをラップすることができます。 FXのアプリケーションスレッド上で実行されているタイムラインの一部であるキーフレーム上の

Timeline timeline = new Timeline(); 
KeyFrame keyFrame = new KeyFrame(Duration.seconds(10), e -> { 
    for (Building building : theSuperKawaiBuildingList) { 
     building.setPopulation(building.getPopulation() + 1); 
    } 
}); 
timeline.getKeyFrames().add(keyFrame); 
timeline.setCycleCount(Animation.INDEFINITE); 
timeline.play(); 

どれハンドラ:

別のアプローチは、(おそらくより良い)JavaFXのアニメーションのAPIを使用することです。

+0

アニメーションAPIを使ってバックグラウンドタスクを実装するのは "邪悪な"ものではありませんか?また、私はもはやそれらの '同期'はもう必要ないと思います... – Odepax

+0

プロパティは、GUIにバインドされていない場合、私はその権利のすべてを心配することなくプロパティを更新することができますか?同様に、この制約はGUIのモノスレッド設計からのみ発生します。 – Odepax

+1

いいえ、それはおそらく、あなたが定期的にやっていること自体が時間がかかっていない限り(あなたが投稿した例の場合)*望ましいアプローチです。時間のかかる作業を定期的に行い、時間のかかる作業の最後にUIを更新する場合は、['ScheduledService'](http://docs.oracle.com/javase/ 8/javafx/api/javafx/concurrent/ScheduledService.html)。 –

関連する問題