2012-04-22 7 views
0

ランダムに配置された5つの円と色のついた円を表示したい。それは簡単な部分でした。今私はこのコードをアニメーションに調整したいと思います。このアプリケーションでは無限に円を生成する必要がありますが、画面上に最後の5つの円しか保持しないという条件があります。これは私が立ち往生したところです。 JavaFxはListChangeListenerを提供します。私はそれを私が使うべきだと思う。しかしどうですか? ListChangeListenerが、それはまだ期待されるように動作しません、エラーなしでコンパイルさせることに成功した後
javafx animation:円を表示

import java.util.Random; 

import javafx.application.Application; 
import javafx.collections.ListChangeListener; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.stage.Stage; 

public class RandomColorTest extends Application { 

    int radius = 20; 
    int sceneWidth = 300; 
    int sceneHeight = 300; 

    private void init(Stage primaryStage) { 
     Group root = new Group(); 
     primaryStage.setResizable(false); 
     primaryStage.setScene(new Scene(root, sceneWidth,sceneHeight)); 

     for (int i = root.getChildren().size(); i < 5; i++) { 
      root.getChildren().add(createCircle()); 
      // the following should convey the idea: 
      // if the collection holds 5 elements then keep least recently generated element for 1 second and then delete it 
      // add one new element 
      // if the collection holds 5 elements then keep least recently generated element for 1 second and then delete it 
      // add one new element 
      // and so on 
      root.getChildren().addListener(new ListChangeListener<E>() { 
       @Override 
       public void onChanged(
         javafx.collections.ListChangeListener.Change<? extends E> arg0) { 
        // TODO Auto-generated method stub 
       } 
      }); 

     } 
    } 

    // Create randomly positioned and colored circle 
    private Circle createCircle() { 
     final Circle circle = new Circle(); 
     circle.setRadius(radius); 

     Random r = new Random(); 
     int rCol1 = r.nextInt(256); 
     int rCol2 = r.nextInt(256); 
     int rCol3 = r.nextInt(256); 
     int rX = radius+r.nextInt(sceneWidth); 
     if (rX>sceneWidth-radius) { 
      rX=rX-2*radius; 
     } 
     int rY = radius+r.nextInt(sceneHeight); 
     if (rY>sceneHeight-radius) { 
      rY=rY-2*radius; 
     } 
     circle.setLayoutX(rX); 
     circle.setLayoutY(rY); 

     circle.setStroke(Color.BLACK); 
     circle.setFill(Color.rgb(rCol1,rCol2,rCol3)); 
     System.out.println(rCol1+"-"+rCol2+"-"+rCol3+"-"+rX+"-"+rY); 
     return circle; 
    } 

    @Override public void start(Stage primaryStage) throws Exception { 
     init(primaryStage); 
     primaryStage.show(); 
    } 
    public static void main(String[] args) { launch(args); } 
} 

:以下 は私の未完成のコードです。ループのために加えられた変更:

for (int i = root.getChildren().size();;i++) { 
      final ObservableList<Node> ol = root.getChildren(); 
      // the following should convey the idea: 
      // if the collection holds 5 elements then keep least recently generated element for 1 second and then delete it 
      // add one new element 
      // if the collection holds 5 elements then keep least recently generated element for 1 second and then delete it 
      // add one new element 
      // and so on 
      ol.add(createCircle()); 
      ol.addListener(new ListChangeListener<Node>(){ 
       @Override 
       public void onChanged(
        javafx.collections.ListChangeListener.Change<? extends Node> arg0) { 
        // TODO Auto-generated method stub 
        System.out.println("one new element added, size:"+ol.size()); 
        if (ol.size()==5) { 
         ol.remove(0); 
        } 
       } 
      }); 
     } 

Forループは無限ループ(また、この問題を解決するために、おそらくない正しい道)に定義されていると私は円が除去され、プログラムの実行時に追加されたコンソールから見ることができます。悲しいかな、もうGUIは見えません。あなたのコードで

答えて

2

、あなたはいくつかのミスがあります:

  • 実行フローが原因init(primaryStage);で無限ループにprimaryStage.show();に到達したことがない、ので、GUIが表示されていないが。
  • 新しいListChangeListenerが繰り返しループに追加されます。ただし、通常の状況では1回だけ追加する必要があります。
  • 新しい変更イベントを再帰的にトリガーする独自のリスナー内のolol.remove(0);)を操作しています。

解決策として、定期的なタスク、長時間のバックグラウンド実行を別のスレッドに分けることができます。

@Override 
    public void start(Stage primaryStage) throws Exception { 
     Group root = new Group(); 
     primaryStage.setResizable(false); 
     primaryStage.setScene(new Scene(root, sceneWidth, sceneHeight)); 

     final ObservableList<Node> ol = root.getChildren(); 

     new Thread(new Runnable() { 
      @Override public void run() { 
       while (true) { 
        try { 
         // Wait for 2 seconds. 
         Thread.sleep(2000); 
        } catch (InterruptedException ex) { 
         ex.printStackTrace(); 
        } 
        Platform.runLater(new Runnable() { 
         @Override public void run() { 
          System.out.println("ol size:" + ol.size()); 
          if (ol.size() == 5) { 
           ol.remove(0); 
          } 
          ol.add(createCircle()); 
         } 
        }); 
       } 
      } 
     }).start(); 
     primaryStage.show(); 
    } 

私はstart(Stage primaryStage)の内容を変更しました。リスナーを追加する必要はありません。このソリューションは非常に高速ですが、エレガントではありません。自分でスレッドを管理する必要があります。よりエレガントで近代的なアプローチについてはWorker Threading in JavaFX 2.0を参照してください。
実際に実際のアニメーションが必要な場合は、Colorful Circles Applicationの例を参照してください。

4

同様の質問も、Oracle forums last yearで尋ねられました。

ここでは、タイムラインを使用したサンプルソリューションがあります。これは、ワーカースレッディングに頼ったソリューションです。両方とも仕事を終えることができますが、私はJavaFXアニメーションAPIをよりエレガントでエラーを起こしにくいものにしています。

import javafx.animation.*; 
import javafx.application.Application; 
import javafx.event.*; 
import javafx.scene.*; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

import java.util.Random; 

public class FiveAutoCircleExample extends Application { 
    private static final Random r = new Random(); 
    public static final int SCENE_SIZE = 800; 

    public static void main(String[] args) throws Exception { launch(args); } 
    public void start(final Stage stage) throws Exception { 
    final Group circles = new Group(); 
    final Timeline animation = new Timeline(
     new KeyFrame(Duration.seconds(.5), 
     new EventHandler<ActionEvent>() { 
     @Override public void handle(ActionEvent actionEvent) { 
      while (circles.getChildren().size() >= 5) circles.getChildren().remove(0); 
      int radius = 10 * r.nextInt(20); 
      circles.getChildren().add(
      new Circle(
       r.nextInt(SCENE_SIZE - radius * 2) + radius, r.nextInt(SCENE_SIZE - radius * 2) + radius, 
       radius, 
       new Color(r.nextDouble(), r.nextDouble(), r.nextDouble(), r.nextDouble()) 
      ) 
     ); 
     } 
     }) 
    ); 
    animation.setCycleCount(Animation.INDEFINITE); 
    animation.play(); 

    // display the scene. 
    stage.setScene(new Scene(circles, SCENE_SIZE, SCENE_SIZE, Color.CORNSILK)); 
    stage.show(); 
    } 
} 
関連する問題