-1

I have created a class called threads with a run() method that is supposed to print a rectangle. I cannot add this thread to the Pane because .add() does not accept threads. How can I successfully upload this thread onto my JavaFX screen? (The idea behind this is that each rectangle generated will be like a new monster, in which these monsters will attack an obstacle, lowering the health of it).

public class Threads implements Runnable {

    @Override
    public void run(){
                Rectangle rect = new Rectangle((int) (Math.random() * 1000), (int) (Math.random() * 1000),100,100);
                rect.setFill(Color.color(Math.random(), Math.random(), Math.random()));
            }      
}

public class SquareThreads extends Application {

    @Override
    public void start(Stage primaryStage) {


        Pane root = new Pane();
        Thread t1 = new Thread(new Threads ());
        t1.start();
        root.getChildren().add(t1);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }      
}
c0der
  • 15,550
  • 6
  • 26
  • 53
  • 1
    JavaFX does not allow for multiple threads to manipulate the scene tree. The way to go is to start the thread asynchronously, let it calculate whatever calculation is necessary and then modify the JavaFX component within [`Platform.runLater(...)`](https://docs.oracle.com/javase/8/javafx/api/javafx/application/Platform.html#runLater-java.lang.Runnable-) – Turing85 Feb 09 '19 at 08:13
  • 1
    Some resources: [Concurrency in JavaFX](https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm) and [`javafx.concurrent`](https://openjfx.io/javadoc/11/javafx.graphics/javafx/concurrent/package-summary.html). – Slaw Feb 09 '19 at 08:14

1 Answers1

2

Assuming you don't want to use JavaFx animation tools, like you did in this previous question, you can have a thread create rectangles in the background, and have your gui respond when new rectangles are created :

import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class SquareThreads extends Application {

    @Override
    public void start(Stage primaryStage) {

        Pane pane = new Pane(); //container for shapes 
        MakeRectangles mr = new MakeRectangles (); //make new shapes on other thread
        mr.getShapes().addListener((ListChangeListener<Shape>) change -> { //respond to shapes added 
            while (change.next()) {
               //if items are removed
               for (Shape s : change.getRemoved()) {
                   Platform.runLater(()->  pane.getChildren().remove(s));
               }
               //if items are added
               for (Shape s : change.getAddedSubList()) {
                   Platform.runLater(()-> pane.getChildren().add(s));
               }
            }
        });

        Scene scene = new Scene(pane,600,600);
        primaryStage.setScene(scene);
        primaryStage.show();
        primaryStage.sizeToScene();
        mr.start(); //start making new rectangles 
    }

    public static void main(String[] args) {
        launch(args);
    }
}

class MakeRectangles implements Runnable {

    //store the shapes created in an observable list 
    private final ObservableList<Shape> shapes;
    private boolean cancel;
    private final Thread t;

    public MakeRectangles() {
        shapes = FXCollections.observableArrayList();
        t= new Thread(this);
    }

    @Override
    public void run(){
        cancel = false;
        while (! cancel){

            Rectangle rect = new Rectangle((int) (Math.random() * 600), (int) (Math.random() * 600),100,100);
            rect.setFill(Color.color(Math.random(), Math.random(), Math.random()));
            shapes.add(rect);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException ex) { ex.printStackTrace();   }
        }
    }

    ObservableList<Shape>  getShapes(){
        return shapes;
    }

    void start(){
        stop(); //stop previous run if any
        t.start();
    }

    void stop(){
        cancel = true;
        try {
            t.join(); //wait for completion
        } catch (InterruptedException ex) { ex.printStackTrace();   }
    }
}

enter image description here

c0der
  • 15,550
  • 6
  • 26
  • 53