Auto Slideshow in JavaFX Pagination - java

I've been using JavaFx lately, as a beginner, and have been very impressed. At the moment I'm stuck trying to set a pagination slideshow to automatically
move the slideshow forward every 5 seconds (and back to the first slide to continue when the last slide is reached). Can any one steer me in the right direction here?
#FXML
public void slideshow(ActionEvent event) {
// TODO Auto-generated method stub
String[] photos = { "housestark.jpg", "housefrey.jpg", "housebar.jpg",
"HouseBolton.jpg", "housegreyjoy.jpg", "houseaaryn.jpg",
"houselannis.jpg", "housemart.jpg", "housereed.jpg",
"housetully.jpg", "housetyrel.jpg", };
Pagination p = new Pagination(photos.length);
p.setPageFactory((Integer pageIndex) -> {
return new ImageView(getClass().getResource(photos[pageIndex])
.toExternalForm());
});
Stage stage = new Stage();
stage.setScene(new Scene(p));
stage.setX(1250);
stage.setY(10);
stage.setTitle("Slideshow");
stage.setResizable(false);
stage.show();
}
This is my code so far! I would appreciate any help anyone could give?

It's pretty easy. All you have to do is create a timer that runs every 5 seconds, and when it runs move the page index.
public class SO extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Pagination p = new Pagination(10);
Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(5), event -> {
int pos = (p.getCurrentPageIndex()+1) % p.getPageCount();
p.setCurrentPageIndex(pos);
}));
fiveSecondsWonder.setCycleCount(Timeline.INDEFINITE);
fiveSecondsWonder.play();
stage.setScene(new Scene(p));
stage.show();
}
}
the five second wonder came from here: JavaFX periodic background task

Related

Javafx: Dialog y position doesn't work properly

Please, consider the following code:
public class JavaFxTest4 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button();
button.setText("dialog");
button.setOnAction((e) -> {
Dialog<?> d = new Dialog<>();
final Window window = d.getDialogPane().getScene().getWindow();
Stage stage = (Stage) window;
stage.setMinHeight(450);
stage.setMaxHeight(450);
stage.setHeight(450);
stage.setMinWidth(600);
stage.setMaxWidth(600);
stage.setWidth(600);
window.setY(300); //<---- note this line
window.setX(660); //<---- note this line
d.showAndWait();
});
VBox root = new VBox();
root.getChildren().addAll(button);
var scene = new Scene(root, 1920, 1000);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As you can see window position is 660 (x) and 300 (y). And this is the result:
As you can see x position is correct, but y position is not. Is this a bug or I misunderstand something? I use javafx 19-ea+3 and openjdk version "14.0.2" on Ubuntu 20.
It is a bug in JavaFX. Issue is here

JavaFX stage issue with hide and show

Im building an application that shows a window that ask the user if he want to suspend the computer with two button options, one of them its a YES and the PC suspends.
The other button named "Later" supposed to hide the window and after an hour it appears again and ask the same question.
Code for the "later buttton"
noButton.setOnAction(event -> {
Done=false; //boolean to close and open the frame
Gui gui = new Gui();
try {
gui.start(classStage);
} catch (Exception e) {
e.printStackTrace();
}
});
The boolean that you see in the code is bc it was the way i think i could control that, trust me i tried in different ways but no one just help me with the issue, here is the code of the GUI class
public class Gui extends Application {
public Stage classStage = new Stage();
public static boolean Done=true;
public static boolean flag=true;
public Gui() {
}
#Override
public void start(Stage primaryStage) throws Exception {
Done = Controller.isDone();
classStage = primaryStage;
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
primaryStage.setX(primaryScreenBounds.getMaxX() - primaryScreenBounds.getWidth());
primaryStage.setY(primaryScreenBounds.getMaxY() - primaryScreenBounds.getHeight());
primaryStage.setAlwaysOnTop(true);
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
primaryStage.setTitle("Alerta suspencion de equipo");
primaryStage.setScene(new Scene(root));
primaryStage.setResizable(false);
primaryStage.initStyle(StageStyle.UNDECORATED);
if (Controller.isDone() == true) {
primaryStage.show();
} else if(Controller.isDone() == false) {
primaryStage.hide();
Platform.exit(); // this is the only way that the windows close
}
}
i know that Platform.exit(); kills the program but when i only use .hide(); of the Stage nothing happens, the window never closed, the worst part is that when i use the Platform.exit() command i cant make the frame appear again...
Anyone knows a way maybe easier to hide and show a window after certain time? maybe im doing this wrong.
Regards.
It's not really clear what's going on in the code in your question. The bottom line is that you should never create an instance of Application yourself; the only Application instance should be the one created for you.
I don't actually see any need to have a separate class for the functionality you've shown (though you could, of course). All you need to do is hide classStage if the no button is pressed, and open it again in an hour:
noButton.setOnAction(event -> {
Done=false; //boolean to close and open the frame
classStage.hide();
PauseTransition oneHourPause = new PauseTransition(Duration.hours(1));
oneHourPause.setOnFinished(e -> showUI(classStage));
oneHourPause.play();
});
// ...
private void showUI(Stage stage) {
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
stage.setX(primaryScreenBounds.getMaxX() - primaryScreenBounds.getWidth());
stage.setY(primaryScreenBounds.getMaxY() - primaryScreenBounds.getHeight());
stage.setAlwaysOnTop(true);
Parent root = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
stage.setTitle("Alerta suspencion de equipo");
stage.setScene(new Scene(root));
stage.setResizable(false);
stage.initStyle(StageStyle.UNDECORATED);
stage.show();
}
Note that the FX Application will exit if the last window is closed, by default. So you should call Platform.setImplicitExit(false); in your init() or start() method.
I am assuming you are reloading the FXML file because the UI might have changed since it was previously loaded. Obviously if that's not the case, all you have to do is show the stage again as it is:
noButton.setOnAction(event -> {
Done=false; //boolean to close and open the frame
classStage.hide();
PauseTransition oneHourPause = new PauseTransition(Duration.hours(1));
oneHourPause.setOnFinished(e -> classStage.show());
oneHourPause.play();
});

Javafx live thread updates

I'm working with Javafx and threads simultaneously and I constanly run into this problem where I make a button and then when the button is clicked (using event handlers) I make a for loop that changes the button to 1,2,3,4,5 and then delays for a second in the middle of each. Like a count down!
But what happens is it delays for 5 seconds and changes the text of button to 5.
The problem is I want to see it change between 1 and 5 but all I see is 5 at the end of a 5 second delay. I would assume that it changing the button text but I don't see it. I might have to to do with the .show() method in the Javafx class.
public class HewoWorld extends Application implements EventHandler<ActionEvent>
{
Thread t = new Thread();
Button butt;
boolean buttWasClicked = false;
Circle circ1 = new Circle(40, 40, 30, Color.RED);
Circle circ2 = new Circle(100, 100, 30, Color.BLUE);
Group root;
Scene scene;
Stage disStage = new Stage();
int i = 1;
public static void main(String[] args)
{
launch(args);
}
public void start(Stage stage) throws Exception
{
disStage.setTitle("tests stuffs");
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
double windh = bounds.getHeight()/2+150;//sets height of screen
double windw = bounds.getWidth()/3;//sets width of screen
Pane layout = new Pane();
butt = new Button();
butt.setText("Hello world");
root = new Group(circ1, circ2, butt);
scene = new Scene(root, 800, 400);
disStage.setWidth(windw);
disStage.setHeight(windh);
butt.setLayoutX(200);
butt.setLayoutY(200);
butt.setOnAction(this);
disStage.setScene(scene);
disStage.show();
}
public void handle(ActionEvent event)
{
if (event.getSource() == butt && buttWasClicked == false)
{
try
{
butt.setText(i+"");
t.sleep(1000);
i++;
}
catch(Exception q)
{
}
circ1 = new Circle(40, 40, 30, Color.BLACK);
circ2 = new Circle(100, 100, 30, Color.RED);
}
}
}
Why your code doesn't work
The reason your code doesn't work is that you are blocking the FX Application Thread.
Like (almost?) all UI toolkits, JavaFX is a single-threaded UI toolkit. This means that all event handlers, and all the rendering of the UI, are performed on a single thread (called the FX Application Thread).
In your code, you have an event handler that takes more than a second to run, because it pauses for a second via a call to Thread.sleep(...). While that event handler is running, the UI cannot be redrawn (because a single thread cannot do two things at once). So while the value of the button's text has changed immediately, the new value won't actually be rendered on the screen until the handle(...) method has finished running. If you had a for loop in the handle method, nothing would be rendered until the entire loop (and anything else in the method) had completed.
How to fix it
The simplest way to do what you want in JavaFX is to use a Timeline to handle the pause. The Timeline manages the threading appropriately for you:
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CountingButton extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Count");
Timeline timeline = new Timeline();
for (int count = 0; count <= 5 ; count++) {
final String text = Integer.toString(count);
KeyFrame frame = new KeyFrame(Duration.seconds(count), event ->
button.setText(text));
timeline.getKeyFrames().add(frame);
}
button.setOnAction(e -> timeline.play());
primaryStage.setScene(new Scene(new StackPane(button), 120, 75));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
In general, for changing the appearance of the user interface at specific time points, the JavaFX Animation API (see also the tutorial) can be useful, especially Timeline and PauseTransition.
A "lower-level" way to do this would be to create a Thread yourself and pause in that thread. This is much more advanced: you need to be careful to update the UI on the FX Application Thread, not on the thread you created. You can do this with a call to Platform.runLater(...):
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class CountingButton extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Start");
button.setOnAction(e -> {
Thread thread = new Thread(() -> {
for (int i = 0; i <= 5 ; i++) {
final String text = "Count: "+i ;
Platform.runLater(() -> button.setText(text));
try {
Thread.sleep(1000);
} catch (InterruptedException exc) {
exc.printStackTrace();
}
}
});
thread.start();
});
primaryStage.setScene(new Scene(new StackPane(button), 120, 75));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
For more general information on threading in JavaFX, have a look at this post: Using threads to make database requests
What you have to do is to replace the thread use by the following method :
scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(
new Runnable(){
#Override
public void run() {
Platform.runLater(new Runnable() {
#Override
public void run() {
//Here your code to change the number by for example incrementig the value of the button
}
});
}
},
1000,
80,
TimeUnit.MILLISECONDS);
+1 if it helps :D
In this case you need a timer to run every second and increment a counter on every hit. To my knowledge, the best way to make a timer in javafx is to use a timeline. https://stackoverflow.com/a/9966213/4683264.
int i = 0;// class field
// ....
Timeline fiveSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), event ->
button.setText(++i)));
fiveSecondsWonder.setCycleCount(5);// repeat five times
fiveSecondsWonder.play();

JavaFX Shape.intersect() performance issue

I have start writing a shooting game JavaFX application. I am using Shape.intersect() to check the collision of bullet and the target. Below is my code and I made it simple so as to post here.
public class TestShapeIntersect extends Application{
AnchorPane anchorPane;
ArrayList<Rectangle> targetObjects;
public static void main(String[] arg){
launch(arg);
}
#Override
public void start(Stage stage) throws Exception {
final Rectangle gun = new Rectangle(50, 50, Color.RED);
anchorPane = new AnchorPane();
anchorPane.getChildren().add(gun);
generateTargetObjects(50); // Number of target objects
anchorPane.getChildren().addAll(targetObjects);
gun.setX(50);
gun.setY(200);
Scene scene = new Scene(anchorPane,300,300,Color.GREEN);
stage.setScene(scene);
stage.show();
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
Rectangle bullet = new Rectangle(5,10,Color.ORANGE);
bullet.setX(75);
bullet.setY(200);
anchorPane.getChildren().add(bullet);
animateBullet(bullet);
}
});
}
private void generateTargetObjects(int noOfTargetObj) {
targetObjects = new ArrayList<Rectangle>();
for(int i=1; i<=noOfTargetObj;i++){
Rectangle rect = new Rectangle(30, 30, Color.YELLOW);
targetObjects.add(rect);
}
}
void animateBullet(final Rectangle bullet){
Timeline timeline = new Timeline();
timeline.setCycleCount(500);
final KeyFrame kf = new KeyFrame(Duration.millis(2), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
bullet.setY(bullet.getY()-1);
checkCollision(bullet);
}
});
timeline.getKeyFrames().add(kf);
timeline.play();
}
//This method will check if there is any collision happened between the bullets and the targets.
//If collision happens then both bullet and target object will be disappeared.
void checkCollision(Rectangle bullet){
int noOfTargetObjs = targetObjects.size();
for(int i=0; i<noOfTargetObjs;i++)
{
if(targetObjects.get(i).isVisible()==true && bullet.isVisible()==true){
Shape intersectShape= Shape.intersect(bullet, targetObjects.get(i));
if(intersectShape.getBoundsInLocal().getWidth() != -1){
targetObjects.get(i).setVisible(false);
bullet.setVisible(false);
}
}
}
}
}
I have not yet aligned the nodes properly.Here the 'gun' rectangle will fire 'bullet' rectangle whenever any key press event is detected.
The problem is for every every first bullet fired in each application session, the very first bullet is not animated properly (means the bullet is not going in it path continuously). But after the first bullet has gone the remaining bullets are animated properly. This performance issue increases with the number of 'target' objects increases.
I have found out that the issue is because of this line:
Shape intersectShape= Shape.intersect(bullet, targetObjects.get(i));
Could anyone let me know why this happens and what could be the solution to resolve this issue? Or is it because of the way that I'm implementing?
I experienced a different behaviour when i executed your application. My first shot was moving fine without any interruptions in the translation. But after several shots the application began to slow down. I tried to improve the performance of your code by doing the following steps:
void animateBullet(final Rectangle bullet){
final Timeline timeline = new Timeline();
timeline.setCycleCount(125); //changed
final KeyFrame kf = new KeyFrame(Duration.millis(16), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
bullet.setY(bullet.getY()-8); //changed
checkCollisionThreaded(bullet); //changed
//added
if(bullet.getX() < 0 || bullet.getX() > bullet.getParent().getBoundsInParent().getWidth()
|| bullet.getY() < 0 || bullet.getY() > bullet.getParent().getBoundsInParent().getHeight())
{
bullet.setVisible(false);
timeline.stop();
AnchorPane ap = (AnchorPane) bullet.getParent();
ap.getChildren().remove(bullet);
}
}
});
timeline.getKeyFrames().add(kf);
timeline.play();
}
Your value for the Duration.millis factor in the KeyFrame was 2, which is not really necessary to run a fluent animation, because JavaFX has a fixed framerate of 60 frame per second, which means that every 16,7 milliseconds a new frame is rendered and displayed. So you can use 16ms as frame-duration without making the animation stutter.
The if-statement checks if the bullet is outside the visible screen, which could happen in your previous code. Non-visible nodes should be removed from the scene graph. It doesn't help if you set a node to setVisible(false), because the node will stay on the scene graph. The Timeline animation should also be stopped, because it would trigger new checkCollision calls. As you can see, i changed the method checkCollision to checkCollisionThreaded. The method is shown below.
public void checkCollisionThreaded(final Rectangle bullet)
{
final int noOfTargetObjs = targetObjects.size();
Task<Integer> t = new Task<Integer>()
{
#Override
protected Integer call() throws Exception
{
for(int i=0; i<noOfTargetObjs;i++)
{
if(targetObjects.get(i).isVisible()==true && bullet.isVisible()==true){
Shape intersectShape= Shape.intersect(bullet, targetObjects.get(i));
if(intersectShape.getBoundsInLocal().getWidth() != -1){
return i;
}
}
}
return -1;
}
#Override
protected void succeeded()
{
super.succeeded();
if(this.getValue().intValue() != -1)
{
Node obj = targetObjects.get(this.getValue().intValue());
obj.setVisible(false);
AnchorPane ap = (AnchorPane) obj.getParent();
ap.getChildren().remove(obj);
targetObjects.remove(this.getValue().intValue());
bullet.setVisible(false);
}
}
};
Thread thread = new Thread(t);
thread.start();
}
There are some violations against the rule "don't touch any objects on the scene graph with a thread different to the JavaFX application thread", but as far as i can see, only reading methods access the scene graph (and it's objects) in the call() method. This method is run on a new Thread, which improves performance. The method succeeded() is run on the JavaFX Application Thread, so that we can safely remove things from our scene graph. I assumed that you want to remove your targets from the scene once they were hit.
It should be said that there might be issues related to the multithreaded code. There could be errors when getting final int noOfTargetObjs = targetObjects.size(); while modifying it on another thread. I left out any synchronization to reduce the complexity of the code.
My guess is that you're sending way too many requests to Shape.intersect(...), which is probably a fairly expensive method to execute. Initially this is causing performance problems, but when the number of calls to the method hits some threshold, the JVM's JIT compiler kicks in and compiles that method, relieving some of the problems. (Again, this is all guesswork.)
Using a TranslateTransition for the bullet and listening to its boundsInParent property to check for collisions seems to work better. I think the reason is that using this technique only checks for collisions when the JavaFX machinery actually moves the bullet. In your code you are performing these checks much more often.
Here's an example.

javafx animation: displaying circles

I want to display 5 randomly positioned and colored circles. It was easy part. Now I want to adjust this code to be an animation. This application should generate random circles endlessly but the condition is that it should keep only last five circles on the screen. This is where I got stuck. JavaFx provides ListChangeListener. I think it is what I should use. But how?
The following is my unfinished code:
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); }
}
After having managed to make ListChangeListener compile without errors it doesn't still work the way expected. Changes made to for loop:
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 loop is defined to loop infinitely (probably not the right way to solve this problem also) and I can see from console that circles are removed and added during the program run. Alas, I can't see GUI anymore.
A similar question was also asked on the on the Oracle forums last year.
Here is sample solution using Timeline, which I prefer to a solution relying on worker threading. Though both can get the job done, I find using the JavaFX animation APIs more elegant and less error prone.
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();
}
}
In your code, you have some mistakes:
the GUI is not shown because, the execution flow never reaches the primaryStage.show(); due to infinite loop in the init(primaryStage);.
new ListChangeListener is added again and again in a loop. However you should add it only once in normal situations.
You are manipulating the ol (ol.remove(0);) in its own listener which triggers the new change event recursively.
As a solution: periodic tasks, long-time background executions can be separated to a different thread.
#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();
}
I have only changed the content of start(Stage primaryStage). There is no need to add a listener. This solution is very quick but not elegant way. You must manage the thread yourself. For more elegant and modern approach refer to Worker Threading in JavaFX 2.0.
In addition, if you really want a real animation then see the example Colorful Circles Application.

Categories