IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 Java Discussion :

[javafx] Problème mise à jour texte Label Chronomètre


Sujet :

Java

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Collégien
    Inscrit en
    Novembre 2017
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Collégien
    Secteur : Conseil

    Informations forums :
    Inscription : Novembre 2017
    Messages : 3
    Points : 5
    Points
    5
    Par défaut [javafx] Problème mise à jour texte Label Chronomètre
    Bonjour à tous,

    Je suis débutant en JavaFX et j'essaye de créer un chronomètre qui démarre à partir du moment ou on appuie sur un bouton.

    Pour le moment, je veux juste faire en sorte qu'il aille jusqu'à 60 secondes.

    J'ai essayé plusieurs méthodes sans réussite malgré mes recherches. Avec mon code, quand j'appuie sur le bouton, le text de mon label ne se met pas à jour.

    (J'arrive à les afficher dans la console Eclipse bien évidemment, mais mon programme plante dès que j'essaie de l'afficher dans ma fenêtre).

    Je vous partage mon code,

    Merci d'avance pour vos réponses.

    Bonne soirée.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     package chrono;
     
    import javafx.application.Application ;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.control.Button;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
     
    public class MainApp extends Application{
    	private int secondes = 0;
    	public void start (Stage primaryStage) throws Exception{
    		primaryStage.setTitle("Mon chronomètre");
     
    		VBox root = new VBox() ;
     
    		Label label = new Label("Temps :");
     
    		Button boutonTemps = new Button("Lancer le chrono");
     
    		boutonTemps.setOnAction(new EventHandler<ActionEvent>() {
     
    			@Override
    			public void handle(ActionEvent e) {	
    				System.out.println("Bouton activé");
     
    						 while (secondes < 60) {
    							  label.setText("Temps :"+secondes+"s");
    							  try {
    								  Thread.sleep(1000);						 
    							  }
    							  catch (InterruptedException z) {
    							  }
    							  secondes++; 
    						 }							
    			}
    		});
     
    		root.getChildren().add(label);
    		root.getChildren().add(boutonTemps);
    		Scene scene = new Scene (root, 600,400);
     
    		primaryStage.setScene(scene);
    		primaryStage.show(); 
    	}
    }

  2. #2
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    2 erreurs classiques de conception :

    1. Tu bloque le thread événementiel du toolkit UI (Event Dispatch Thread dans AWT/Swing, JavaFX application thread ici) par un sleep() - il ne faut JAMAIS faire cela.
    2. Tu effectues toute ton action dans le thread événementiel et donc forcement aucune valeur intermédiaire sera affichée puisque de toutes manières l'UI s'est jamais mise a jour entre le début et la fin de l'action.


    Solution : utiliser un autre thread pour faire l'horloge. JavaFX a des classes dediees pour les grosses taches (Service et Task) pour cela mais vu qu'ici c'est tres simple (juste un timer), on va rester sur une solution basique a base de Thread. même si pas forcement joli :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    label.setText(String.format("Temps : %ds", 0));
    Thread t = new thread(() -> {
      for (int secondes = 0 ; !Thread.currentThread.isInterrupted() && secondes < 60 ; secondes++) {
        try {
    	Thread.sleep(1000);						 
        }
        catch (InterruptedException z) {
          // Log ou afficher l'erreur !!!
        }
        secondes++; 
        // La maj du label doit se faire sur le FXAppThread.
        Plaform.runLater(() ->  label.setText(String.format("Temps : %ds", secondes)));
      }			
    }
    t.setPriority(Thread.MIN_PRIORITY);
    t.start();
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  3. #3
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 840
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 840
    Points : 22 854
    Points
    22 854
    Billets dans le blog
    51
    Par défaut
    Bon, puisque je m’adresse a un collégien, je vais essayer de faire une explication un peu simple du pourquoi ça marche comme ça histoire que tu comprennes mieux. En espérant que d'autres en prennent de la graine.

    De manière générale, lorsque tu exécutes un programme, les instructions se déroulent dans ce qu'on appelle un fil d’exécution (thread), les unes après les autres (linéairement).
    Par exemple un programme qui fait

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    System.out.println("Hello World!");
    System.out.println("Salut le monde !");
    Cela peut se représenter ainsi :

    Nom : 2020-05-28-thread1.png
Affichages : 740
Taille : 4,8 Ko

    Les choses deviennent un peu plus complexes lorsqu'on fait des interfaces graphiques. En général, la boite a outils (toolkit) dispose de son propre thread en plus du fil d’exécution du programme principal. Ce thread se lance quand la boite a outil est initialisée et se termine quand on ferme la fenêtre et que cela arrête le programme. Donc, en général, tu n'as pas à t'en occuper. Dans AWT, Swing ou JavaFX, ce thread alterne très rapidement entre deux états :
    • le traitement des événements
    • l'affichage


    On peu le représenter ainsi :

    Nom : 2020-05-28-thread2.png
Affichages : 765
Taille : 8,4 Ko

    Lorsqu'on traite un événement e (ex: clic sur un bouton) c'est toujours dans la partie événement du thread. Et l'affichage a se fait toujours dans la partie affichage. En AWT et Swing on peut écrire du code qui s’exécute directement dans la partie affichage, en JavaFX on ne peut pas.

    Donc ce thread du toolkit est comme une espèce de cœur qui bat et qui permet a l'interface graphique de vivre : réagir a des événements et afficher des choses (partie encadrée en jaune). En JavaFX, il y a environ 60 battements de cœurs par seconde (60 fps = 60 frame per second = fréquence).

    Lorsque tu fais un sleep() dans ce thread ou quand tu fais un très long traitement dans ce thread, tu parasites la fréquence de rafraîchissement en rallongeant artificiellement la durée de la partie traitement des événements. Durant tout le temps durant le quel le thread dors ou fait le traitement, l'interface graphique ne peut plus répondre aux saisies utilisateurs ou même actualiser son contenu. Cela peut aussi provoquer des bogues ou des plantages du programme. Parfois l'utilisateur peut croire que le programme est planté et va fermer l'application sans comprendre que le programme continuait à fonctionner même si l'interface graphique ne répondait plus.

    Nom : 2020-05-28-thread3.png
Affichages : 752
Taille : 8,0 Ko

    Cela explique pourquoi ton label est totalement incapable d'afficher les étapes intermédiaires de ta boucle et se contente d'afficher la valeur finale.

    Notre but ici est donc, lorsqu'on clique sur le bouton (e), de créer un nouveau fil d’exécution qui va faire défiler le temps en parallèle du thread du toolkit. Comme ce nouveau thread est totalement indépendant du premier, il peut sans soucis dormir ou effectuer un traitement long.

    Cela donne quelques chose comme ceci.

    Nom : 2020-05-28-thread4.png
Affichages : 818
Taille : 23,5 Ko

    À intervalles réguliers, nous injectons des modifications de la valeur du texte du label dans les événements du thread du toolkit (en invoquant Platform.runLater()). Il se peut que, lorsque notre fréquence de mise à jour est trop rapide, certaines valeurs soient peut-être perdues en cours de route (ici sur le schéma e0 ou encore e59), mais ce n'est pas bien grave puisque l'utilisateur aura l'illusion que le compteur fait défiler toutes les secondes.
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

Discussions similaires

  1. [Python 3.x] Problème mise à jour label
    Par Supernatural dans le forum Général Python
    Réponses: 2
    Dernier message: 23/10/2018, 15h42
  2. Réponses: 10
    Dernier message: 14/10/2016, 15h46
  3. [2014] Problème mise à jour temps réel full-text
    Par Lelebap dans le forum Développement
    Réponses: 5
    Dernier message: 04/05/2016, 11h04
  4. Mise à jour texte label
    Par TheMelon dans le forum GTK+ avec Python
    Réponses: 7
    Dernier message: 23/02/2010, 14h24
  5. Problème mise à jour textvariable d'un Label
    Par Le ChIeN fOu dans le forum Tkinter
    Réponses: 7
    Dernier message: 23/05/2009, 23h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo