JavaFX Label lässt sich nicht mehrmals färben

DerDecane

Aktives Mitglied
Hey Leute, ich schreibe gerade an einem Programm in dem ich ein leeres Label erstellen muss und das rot und grau blinken lassen muss. Da das irgendwie nicht funktioniert habe ich eine Testklasse geschrieben um mir die Denkweise anzueignen.
Code:
package meldetafel;

import javafx.application.Application;
...

public class Testklasse extends Application {

    @Override
    public void start(Stage primaryStage) throws InterruptedException {
       
        Label Signalfeld = new Label();
        Signalfeld.setPrefSize(100, 100);
        HBox box = new HBox(10);
        box.getChildren().add(Signalfeld);
       
        primaryStage.setScene(new Scene(box));
        primaryStage.show();
       
       
            Signalfeld.setStyle("-fx-background-color: grey;");
            System.out.println("grey");
            Thread.sleep(500);
            Signalfeld.setStyle("-fx-background-color: green;");
            System.out.println("green");
            Thread.sleep(500);
            Signalfeld.setStyle("-fx-background-color: blue;");
            System.out.println("blue");
            Thread.sleep(500);
            Signalfeld.setStyle("-fx-background-color: red;");
            System.out.println("red");
 
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Was jetzt passieren sollte wenn ich das Programm starte ist, dass das Feld grau ist und in der Konsole grey ausgegeben wird. Nach 500ms Wartezeit sollte es dann grün werden und es sollte grün ausgegeben werden usw.

Was aber wirklich passiert und was mich total irritiert ist folgendes:

Das Feld bleibt grau, es wird grau ausgegeben. Nach der Wartezeit bleibt das Feld immernoch grau und es wird green ausgegeben. Nach einer weiteren Wartezeit bleibt das Feld immernoch grau und es wird blue ausgegeben. Nach der nächsten Wartezeit wird das Feld plötzlich rot und es wird red ausgegeben. Sprich er gibt zwar die Wörter aus (das habe ich als Kontrolle eingefügt) aber färbt das Feld nur beim letzten "Befehl" und nicht schon vorher.

Mach ich da irgendwas falsch?
 
Das ganze ist eine Schulaufgabe, ich weiß von anderen dass es auch ohne seperate Threads geht weil mir das einige gesagt haben. Allerdings erreiche ich mal wieder niemanden (immer wenns drauf ankommt -.-)
 
Ja vielleicht bietet JavaFX hier noch andere Möglichkeiten an, im Grunde läuft es aber darauf hinaus das diese Verarbeitung in einen 2.Thread läuft 😉 (ob man diesen nun bewusst selber erstellt oder das Framework hier im Hintergrund zaubert)

Das Problem bei dir ist wie oben schon gesagt: JavaFX läuft in einem Thread, wenn du diesen schlafen legst (mit dem Thread.sleep(500)) kann sich die Oberfläche nicht neu zeichnen.
 
Ja aber theoretisch müsste der Thread doch 500ms "schlafen" dann aufwachen, das Feld färben und die Farbe in der Konsole ausgeben und wieder 500ms "schlafen".
 
Nicht ganz, dein Thread läuft ja innerhalb des JavaFx-Threads.
Er wird nicht seperat ausgeführt.
Die GUI bekommt dadurch nicht 500ms Zeit, um sich neu zu zeichnen.
Sondern wartet die GUI erst, bis die Verarbeitung abgearbeitet ist mit dem neu Zeichnen.
 
Es geht auch mit einer Timeline. Der macht aber am Ende auch nen separaten Thread.

So in etwas könnte man es machen:
Java:
package application;

import java.util.concurrent.atomic.AtomicInteger;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class BlinkMain extends Application {
   
    @Override
    public void start(Stage primaryStage) throws InterruptedException {
       
        Label signalfeld = new Label();
        signalfeld.setPrefSize(100, 100);
        HBox box = new HBox(10);
        box.getChildren().add(signalfeld);
       
        primaryStage.setScene(new Scene(box));
        primaryStage.show();
       
        AtomicInteger counter = new AtomicInteger(0);
        final Timeline tl = new Timeline(new KeyFrame(Duration.millis(500), new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                switch (counter.getAndIncrement()) {
                case 0:
                    signalfeld.setStyle("-fx-background-color: grey;");
                    break;
                case 1:
                    signalfeld.setStyle("-fx-background-color: green;");
                    break;
                case 2:
                    signalfeld.setStyle("-fx-background-color: blue;");
                    break;
                case 3:
                    signalfeld.setStyle("-fx-background-color: red;");
                    break;
                default:
                    signalfeld.setStyle("-fx-background-color: black;");
                    break;
                }
            }
        }));
        tl.cycleCountProperty().set(4);
        tl.play();
    }
   
    public static void main(String[] args) {
        launch(args);
    }
}

Noch ein Hinweis: Da du ja noch am Lernen bist, gewöhne dir bitte den Java Code Style an. Stein des Anstosses: In Java beginnen Variablen mit kleinem Buchstaben.
 

Zurück
Oben