I have an application that can create a rectangle that decreases in size for example a lapse of time of 10 sec, but here is when I try to shrink the rectangle, the window bug (nothing is displayed in the scene) and wait until the countdown is finished to stop bugging (and then display the rectangle not diminished). I tried to find on the Internet the equivalent of repaint in Swing but not average: / this.requestLayout () -> I found this on the internet but it does not work. Here is my code of my countdown:
public class Compteur {
DemoBorderPane p ;
public DemoBorderPane getPan() {
if(p==null) {
p = new DemoBorderPane();
}
return p;
}
public Compteur() {
}
public void lancerCompteur() throws InterruptedException {
int leTempsEnMillisecondes=1000;
for (int i=5;i>=0;i--) {
try {
Thread.sleep (leTempsEnMillisecondes);
}
catch (InterruptedException e) {
System.out.print("erreur");
}
System.out.println(i);
getPan().diminuerRect(35);
}
}
}
There is my Borderpane code :
public class DemoBorderPane extends BorderPane {
private Rectangle r;
public Rectangle getRect() {
if(r==null) {
r = new Rectangle();
r.setWidth(350);
r.setHeight(100);
r.setArcWidth(30);
r.setArcHeight(30);
r.setFill( //on remplie notre rectangle avec un dégradé
new LinearGradient(0f, 0f, 0f, 1f, true, CycleMethod.NO_CYCLE,
new Stop[] {
new Stop(0, Color.web("#333333")),
new Stop(1, Color.web("#000000"))
}
)
);
}
return r;
}
public void diminuerRect(int a) {
getRect().setWidth(getRect().getWidth()-a);
int c= (int) (getRect().getWidth()-a);
System.out.println(c);
this.requestLayout();
//this.requestFocus();
}
public DemoBorderPane() {
this.setBottom(getRect());
}
}
There is my Main code :
public class Main extends Application {
private DemoBorderPane p;
public DemoBorderPane getPan() {
if(p==null) {
p = new DemoBorderPane();
}
return p;
}
@Override
public void start(Stage primaryStage) {
Compteur c = new Compteur();
try {
//Group root = new Group();
Scene scene = new Scene(getPan(),800,600);
//scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
//root.getChildren().add(getPan());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
try {
c.lancerCompteur();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
/*Son s = null;
try {
s = new Son();
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
s.volume(0.1);
s.jouer();
c.lancerCompteur();
s.arreter();*/
}
}
Thank ;)
As long as you keep the JavaFX application thread busy it cannot perform layout/rendering. For this reason it's important to make sure any methods that run on the application thread, like e.g. Application.start
or event handlers on input events return fast.
lancerCompteur
however blocks the application thread for 5 seconds so the only result you see is the final one after the method completes.
In general you can run code like this on a different thread and use Platform.runLater
to update the ui.
In this case you could take advantage of the Timeline
class which allows you to trigger an event handler on the application thread after a given delay:
@Override
public void start(Stage primaryStage) {
Scene scene = new Scene(getPan(), 800, 600);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), event -> {
getPan().diminuerRect(35);
}));
timeline.setCycleCount(5);
timeline.play();
primaryStage.setScene(scene);
primaryStage.show();
}
DemoBorderPane
in your Main
class and the Compteur
class; the Rectangle
shown in the scene was never subject to an update.requestLayout
in diminuerRect
. This happens automatically when the Rectangle
's size is modified.DemoBorderPane.getRect
is invoked from it's constructor so moving the initialisation to the constructor would allow you to get rid of the if
check without affecting functionality.