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 :

Rafraichir régulièrement un dessin après un évènement : avec Timer et pas Thread.sleep


Sujet :

Java

  1. #1
    Invité
    Invité(e)
    Par défaut Rafraichir régulièrement un dessin après un évènement : avec Timer et pas Thread.sleep
    Bonjour,

    J'ai un dessin (Graphics) qui doit se rafraichir à intervalles réguliers (environ une fois par seconde). Le rafraichissement se déroule bien lorsqu'il est demandé par le programme principal. Mais lorsqu'il est demandé par un évènement (clic de bouton), seul le résultat final est affiché, et pas les dessins intermédiaires.

    J'utilise la fonction Thread.sleep pour séparer deux affichages.

    J'ai essayé de réduire au minimum mon code tout en laissant le problème apparant ... du coup il n'est pas "joli", mais il est court.

    Ce code dessine un carré noir alternativement à gauche puis à droite de la fenêtre (cinq fois). Ensuite il y a un bouton qui permet de relancer le dessin du carré noir alternativement des deux côtés (pour cinq dessins).

    Lorsqu'on lance le programme, les cinq premiers dessins sont bien affichés car ils n'ont pas été demandés par un clique de bouton. Ensuite lorsqu'on clic sur le bouton, rien ne se passe, et au bout des cinq itérations, le dessin final est affiché.

    Voici le code :

    imports
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;

    classe Fenetre
    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
    public class Fenetre extends JFrame {
      int x = 0;
     
      public static void main(String[] args) {
        new Fenetre();
      }
     
      Fenetre() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200, 150);
     
        Bouton avancerCinqFois = new Bouton(this);
        avancerCinqFois.addActionListener(new GestionEvenement());
        add(avancerCinqFois, BorderLayout.SOUTH);
     
        setVisible(true);
     
        avancerCinqFois();
      }
     
      void avancerUneFois() {
        x = (x+100) % 200;
        repaint();
      }
     
      void avancerCinqFois() {
        for (int i = 0; i < 5; ++i) {
          avancerUneFois();
          try {Thread.sleep(500);}
          catch (InterruptedException e) { }
        }
      }
     
      public void paint(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0, 0, 200, 100);
        g.setColor(Color.black);
        g.fillRect(x, 0, 100, 100);
      }
    }
    classe Bouton
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Bouton extends JButton {
      Fenetre fenetre;
     
      Bouton(Fenetre fenetre) {
        super("avancer 5 fois");
        this.fenetre = fenetre;
      }
    }
    classe GestionEvenement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class GestionEvenement implements ActionListener {
      public void actionPerformed(ActionEvent evenement) {
        Bouton bouton = (Bouton)evenement.getSource();
        bouton.fenetre.avancerCinqFois();
      }
    }
    Quelqu'un as-t'il déjà eu le problème ?
    Dernière modification par Invité ; 03/03/2010 à 09h00. Motif: mettre la solution dans le titre

  2. #2
    Expert éminent sénior
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Le problème vient du fait que tu utilise Thread.sleep dans le thread courant. Le thread dans lequel tu te trouve à ce moment là est celui de l'interface graphique, autrement dit celui de toutes les opérations de dessin. Or en faisant un Thread.sleep to bloque toutes les opérations dans ce thread, donc tout dessin.

    Une lecture obligatoire pour comprendre les interactions entre Swing et les threads: http://gfx.developpez.com/tutoriel/j...ing-threading/

    Je te conseille donc de plutôt passer par un timer swing s'activant toutes les secondes:

    http://java.sun.com/docs/books/tutor...isc/timer.html

  3. #3
    Invité
    Invité(e)
    Par défaut
    Merci pour cette réponse, il est très instructif cet article.

    Le timer est exactement ce qu'il me fallait. Je met le code modifié qui marche, ça pourra toujours servir à quelqu'un.

    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
     
    public class Fenetre extends JFrame {
      int x = 0;
      Timer timer;
     
      public static void main(String[] args) {
        new Fenetre();
      }
     
      Fenetre() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200, 150);
     
        ActionListener avancerUneFois = new ActionListener() {
          public void actionPerformed(ActionEvent evenement) {
            avancerUneFois();
          }
        };
        timer = new Timer(500, avancerUneFois);
     
        Bouton commencerAvancer = new Bouton(this);
        commencerAvancer.addActionListener(new GestionEvenement());
        add(commencerAvancer, BorderLayout.SOUTH);
     
        setVisible(true);
      }
     
      void avancerUneFois() {
        x = (x+100) % 200;
        repaint();
      }
     
      public void paint(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0, 0, 200, 100);
        g.setColor(Color.black);
        g.fillRect(x, 0, 100, 100);
      }
    }
     
    class Bouton extends JButton {
      Fenetre fenetre;
     
      Bouton(Fenetre fenetre) {
        super("commencer à avancer");
        this.fenetre = fenetre;
      }
    }
     
    class GestionEvenement implements ActionListener {
      public void actionPerformed(ActionEvent evenement) {
        Bouton bouton = (Bouton)evenement.getSource();
        bouton.fenetre.timer.start();
      }
    }

  4. #4
    Invité
    Invité(e)
    Par défaut
    Nan en fait j'ai encore une question (désolé du double post ).

    Je me demande si les gens font comme ça d'habitude pour le gestion d'évènements :
    - créer une nouvelle classe qui étend JButton afin de lui ajouter un attribut Timer
    - créer une nouvelle classe qui étend Timer afin de lui ajouter un attribut JPanel

    En fait je suis obligé de faire ça car dans la fonction "actionPerformed", je n'ai pas accès à l'objet dont j'ai besoin, je n'ai accès qu'à la source de l'évènement via la fonction "getSource()".

    Est-ce comme ça qu'il faut procéder ou d'une autre manière ?

    Je met mon code relatif à la gestion des évènements :
    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
    class BoutonAction extends JButton {
      MonTimer timer;
     
      BoutonAction(String texte, MonTimer timer) {
        super(texte);
        this.timer = timer;
      }
    }
     
    class MonTimer extends Timer {
      Fenetre fenetre;
     
      MonTimer(int delai, ActionListener action, Fenetre fenetre) {
        super(delai, action);
        this.fenetre = fenetre;
      }
    }
     
    class GestionEvenements implements ActionListener {
      public void actionPerformed(ActionEvent evenement) {
        if (evenement.getSource() instanceof BoutonAction) {
          BoutonAction bouton = (BoutonAction)evenement.getSource();
          bouton.timer.start();
        }
        else if (evenement.getSource() instanceof MonTimer) {
          MonTimer timer = (MonTimer)evenement.getSource();
          timer.fenetre.avancerUneFois();
        }
      }
    }

  5. #5
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 274
    Points : 4 141
    Points
    4 141
    Par défaut
    Cela ne sert à rien de redéfinir un JButton si tu ne lui apportes rien de plus que la classe de base.

    Si tu veux une référence à un objet (issu d'une autre classe) dans ta méthode actionPerformed, il suffit de lui passer au constructeur de cette classe.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Mais bien sur ! C'est tellement simple que je me demande pourquoi je n'y ai pas pensé. Merci !

    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
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
     
    public class Fenetre extends JFrame implements ActionListener {
      int x = 0;
      Timer timer;
     
      public static void main(String[] args) {
        new Fenetre();
      }
     
      Fenetre() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200, 150);
     
        timer = new Timer(500, this);
     
        JButton bouton = new JButton("démarrer le timer");
        bouton.addActionListener(this);
        add(bouton, BorderLayout.SOUTH);
     
        setVisible(true);
      }
     
      void avancerUneFois() {
        x = (x+100) % 200;
        repaint();
      }
     
      public void paint(Graphics g) {
        g.setColor(Color.white);
        g.fillRect(0, 0, 200, 100);
        g.setColor(Color.black);
        g.fillRect(x, 0, 100, 100);
      }
     
      public void actionPerformed(ActionEvent evenement) {
        if (evenement.getSource() instanceof JButton)
          timer.start();
        else if (evenement.getSource() instanceof Timer)
          avancerUneFois();
      }
    }
    Dernière modification par Invité ; 03/03/2010 à 18h21. Motif: amélioration du code

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Gestions évènements avec souris - Dessiner avec souris
    Par CosaNostra dans le forum Débuter
    Réponses: 10
    Dernier message: 23/01/2010, 10h05
  2. JButton avec boucle while contenant thread.sleep(1000)
    Par v4np13 dans le forum AWT/Swing
    Réponses: 1
    Dernier message: 17/10/2007, 20h31
  3. update d'après 2 tables avec ordre de date
    Par fred23195 dans le forum Langage SQL
    Réponses: 1
    Dernier message: 22/12/2005, 17h39
  4. Réponses: 1
    Dernier message: 21/10/2005, 13h08
  5. Rafraichir une iframe 1 après modification d'une iframe2
    Par MASSAKA dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 12/10/2005, 11h47

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