I'm doing a school project, I have to make the animation of a "ball", which is nothing more than a label with a CSS style that turns the label into a red circle.
I have to make the ball move in a certain direction, I already have that. But it occurred to me to try moving 2 balls at the same time, each ball with its own thread...
Create a class, called "movement", which inherits from Thread , in which I receive a Label, an AnchorPane (to know the coordinates of the edges, which are limiting) and a boolean, to know whether to move left or right, if I execute only one thread, the program runs fine, but if I launch the threads, that is, 2 instances of the movement class , one works perfectly, but the other stops.
How could I make the two "balls" move?
The first string is ball V, and the second string is ball A.
This is my code:
main class
public class U3HilosAnimar0002 extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("pelot.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The FXML Controller
Here I receive the click of the Start button, to start the movement
package u3hilosanimar0002;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
public class PelotController implements Initializable {
@FXML
private Label lbl;
@FXML
private Button btnStart;
@FXML
private AnchorPane APfondo;
@FXML
private Label lbl2;
@FXML
private AnchorPane AP2;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
@FXML
private void startHilo(ActionEvent event) throws InterruptedException {
Movimiento m1 = new Movimiento(lbl,APfondo,true);
Movimiento m2 = new Movimiento(lbl2,APfondo,false);
m1.start();
System.out.println("Segundo Hilo");
m2.start();
}
}
Movement class that inherits from Thread
package u3hilosanimar0002;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
/**
*
* @author ESPINO
*/
public class Movimiento extends Thread {
int c;
Label pelota = new Label();
AnchorPane AP;
private boolean direccion;
Movimiento(Label lbl, AnchorPane APfondo,boolean direccion) {
c=5;
this.pelota = lbl;
this.AP = APfondo;
this.direccion = direccion;//flse left , true derech
}
@Override
public void run(){
while(true){
if(this.pelota.getLayoutX()+this.pelota.getWidth()>AP.getWidth()||this.pelota.getLayoutX()<0){
//hará que rebote a la direccion opuesta, cuando llegué a la derecha del todo
c*=(-1);
//Thread.interrupted();
//break;
}
try {
//if(direccion){
this.pelota.setLayoutX(this.pelota.getLayoutX()+c);
//direccion = false;
//}
//else{
// this.pelota.setLayoutX(this.pelota.getLayoutX()-c);
//direccion =false;
//}
sleep(35);
} catch (InterruptedException ex) {
Logger.getLogger(Movimiento.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane id="AnchorPane" fx:id="APfondo" prefHeight="400.0" prefWidth="645.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="u3hilosanimar0002.PelotController">
<stylesheets>
<URL value="@pelot.css" />
</stylesheets>
<children>
<AnchorPane fx:id="AP2" prefHeight="400.0" prefWidth="645.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Label fx:id="lbl" alignment="CENTER" contentDisplay="CENTER" layoutX="278.0" layoutY="177.0" prefHeight="46.0" prefWidth="44.0" text="V" textFill="WHITE">
<font>
<Font size="28.0" />
</font></Label>
<Button fx:id="btnStart" layoutX="253.0" layoutY="345.0" mnemonicParsing="false" onAction="#startHilo" prefHeight="25.0" prefWidth="95.0" text="Start" />
<Label fx:id="lbl2" alignment="CENTER" contentDisplay="CENTER" layoutX="278.0" layoutY="98.0" prefHeight="46.0" prefWidth="44.0" text="A" textFill="WHITE">
<font>
<Font size="28.0" />
</font>
</Label>
</children>
</AnchorPane>
When working with JavaFX applications you should avoid updating the GUI from threads other than the JavaFX Application Thread. This is the main thread of JavaFX applications and is in charge of handling all the tasks related to the UI. If you try to do these updates on separate threads, sometimes exceptions are thrown and other times, like yours, you get weird and seemingly unexplained behavior.
Salution: The line where you update the position of the Label execute it with the Platform.runLater() methods , like this:
You can learn a bit more about concurrency in JavaFX here .