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 :

[Swing] Bouger un cercle en temps réel


Sujet :

Java

  1. #1
    Membre régulier Avatar de Fahelis
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2014
    Messages : 77
    Points : 87
    Points
    87
    Par défaut [Swing] Bouger un cercle en temps réel
    Bonjour,
    Je suis actuellement en train de débuter dans les interfaces graphiques et j'ai un petit souci.
    J'ai créé une classe Fenetre héritant de JFrame, et une classe ZoneDessin héritant de JPanel.
    Dans ma classe ZoneDessin, j'ai la méthode suivante pour créer un rond rouge.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void paintComponent(Graphics graph){
            graph.setColor(Color.red);
            graph.fillOval(this.x, this.y, 50, 50);
        }
    Dans mon main, j'instancie ma classe Fenetre et j'appelle ma méthode dans laquelle j'instancie ZoneDessin.
    Jusque là pas de souci, j'obtiens bien mon rond rouge.

    Pour la suite, je cherche à la déplacer, j'ai donc créé une boucle modifiant ses coordonnées et appelant la méthode repaint suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public void repaint(){
            ZoneDessin panneauDessin = new ZoneDessin(this.x, this.y);
            this.setContentPane(panneauDessin);
        }
    Et c'est là que commence mon souci. Le tout fonctionne très bien (J'utilise Thread.sleep pour ralentir mon cercle), mais pour le voir effectivement bouger, je dois avec ma souris modifier en continue la taille de ma fenêtre. Si je ne touche à rien, je ne vois rien. Si je redimensionne constamment ma fenêtre, je vois bien mon cercle bouger.

    J'imagine qu'en plus ça doit être quelque chose de très simple, mais cela me laisse perplexe.

    Merci à ceux qui auront pris la peine de me lire, en espérant avoir été suffisamment clair
    Pensez au bouton quand votre problème est réglé afin de ne pas faire perdre leur temps aux gens qui essayent gentiment d'aider les autres

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Tout d'abord, la méthode repaint() est une méthode qui sert à demander qu'un composant graphique soit redessiné, à la suite d'un changement qui le nécessite. En effet, SWING ne pouvant pas savoir qu'un changement nécessite un rafraîchissement, il ne le fait pas tout seul. Ici, tu redéfinis la méthode repaint() sans appeler la méthode repaint() standard de l'API (par un super.repaint()) : la méthode ne fait que changer le contentPane et c'est tout. L'UI se met à jour quand tu déplaces la souris, parce que cela fait partie des mécanismes standard de redessin de frame. Il y a un second problème : il ne suffit pas qu'un composant soit dans une fenêtre pour qu'il soit visible, il faut qu'il ait également un emplacement et une taille : on appelle ça le layout. Pour l'emplacement, pas de problème : l'emplacement par défaut est en haut à gauche. Pour la taille, par contre, même si elle est déterminée automatiquement par défaut, il faut également indiquer que quelque chose à changer pour que layout se (re)fasse.

    Au lieu de faire ton code dans repaint(), fait une méthode dédiée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void changePanel() {
    ZoneDessin panneauDessin = new ZoneDessin(this.x, this.y);
            this.setContentPane(panneauDessin);
    panneauDessin.revalidate(); // ceci est suffisant pour indiquer que le layout doit être refait et que le composant soit redessiné
    }
    Ensuite, il faut que tu fasses attention à une chose : si ta boucle s'effectue dans le thread de Swing (celui qu'on appelle EDT, Event Dispatcher Thread)), tu vas empêcher l'UI se se mettre à jour. En effet, un thread de ne peut faire qu'une seule chose à la fois. Or l'EDT est chargé de rafraîchir l'affichage. Si l'EDT est occupé à boucler, pas de rafraîchissement. Il faut donc faire ta boucle dans un thread différent de l'EDT. Et passer la main à l'EDT, lorsque c'est nécessaire.

    Par ailleurs, tu aurais intérêt à faire un JPanel (ou un Canvas) qui s'occupe de dessiner un cercle à différents endroits, plutôt que de changer le panel sans arrêt, pour avoir un mouvement plus fluide (bien que cela ne sera pas complètement le cas, pour d'autres raisons, que tu verras plus tard (si ça t'intéresse, regardes BufferStrategy).

    Voici un exemple :

    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
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    public class SampleAnimPanel {
     
    	public static void main(String[] args) {
     
    		final JFrame frame = new JFrame();
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    		final AnimationPanel panel=new AnimationPanel();
    		frame.setContentPane(panel);
     
    		frame.addWindowListener(new WindowAdapter() {
    			private Thread thread;
     
    			@Override
    			public void windowOpened(WindowEvent e) {
    				thread=new Thread() {
    					private boolean running;
     
    					@Override
    					public void run() {
    						running = true;
    						while(running )
    						for(double angle=0; running && angle<Math.PI*2; angle+=0.1) {
    							int centerx = panel.getWidth()/2;
    							int centery = panel.getHeight()/2;
    							int x=(int) (centerx+70*Math.cos(angle)) - AnimationPanel.DIAMETRE/2;
    							int y=(int) (centery+70*Math.sin(angle)) - AnimationPanel.DIAMETRE/2;
    							panel.setPosition(x, y);
    							try {
    								sleep(30);
    							} catch (InterruptedException e) {
    								running=false;
    							}
    						}
    					}
     
    					@Override
    					public void interrupt() {
    						running=false;
    						super.interrupt();
    					}
    				};
    				thread.start();
    			}
     
    			@Override
    			public void windowClosed(WindowEvent e) {
    				thread.interrupt();
    			}
    		});
     
    		frame.setSize(200, 200);
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
     
    	}
     
    	private static class AnimationPanel extends JPanel {
     
    		public static final int DIAMETRE = 20;
    		private int x;
    		private int y;
     
    		public AnimationPanel() {
    		}
     
    		public void setPosition(int x, int y) {
    			this.x=x;
    			this.y=y;
    			repaint(); // on demande de redessiner, parce que x et y ont changé, et que le dessin doit changer en conséquence
    		}
     
    		@Override
    		public void paint(Graphics g) {
    			super.paint(g);
    			g.setColor(Color.BLUE);
    			g.fillOval(x, y, DIAMETRE, DIAMETRE);
    		}
     
    	}
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre régulier Avatar de Fahelis
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2014
    Messages : 77
    Points : 87
    Points
    87
    Par défaut
    J'ai utilisé "revalidate" comme tu l'a conseillé. Cela affichait bien les déplacement en temps réel mais "peignait" le chemin, la boule se déplaçait laissant une trainée de couleur sur son passage.
    En remplaçant la méthode "paintComponent" par "paint" cela a réglé le problème, mais je n'ai pas bien compris pourquoi. Je vais me pencher sur le détails de ces deux méthodes, ainsi que sur ton code (que j'ai testé, mais pas encore regardé en détail).

    Merci beaucoup pour ta réponse, très rapide qui plus est
    Pensez au bouton quand votre problème est réglé afin de ne pas faire perdre leur temps aux gens qui essayent gentiment d'aider les autres

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par WilliamLeSanguinaire Voir le message
    En remplaçant la méthode "paintComponent" par "paint" cela a réglé le problème, mais je n'ai pas bien compris pourquoi.
    C'est la méthode paintComponent(Graphics) de JPanel qui vide le "fond", si le JPanel est configuré comme opaque. Si tu redéfinis cette méthode sans appeler super.setPaintComponent(Graphics), tu "supprimes" l'exécution du code qui s'occupe de ça. C'est également le cas si tu redéfinis paint(Graphics), sans appeler super.paint(Graphics), puisque c'est cette méthode qui va faire que paintComponent(Graphics) est appelée. Attention, toutefois, ce n'est pas un moyen de garder une trace de ce qui a été dessiné. C'est simplement que l'instance de contexte graphique (l'instance de Graphics) qui est recyclée, mais on a aucun contrôle sur ce recyclage. Un autre composant graphique peut s'en servir pour dessiner, elle peut être vidée par certains mécanismes de Swing (redimensionner une fenêtre par exemple), et je suppose qu'on peut même obtenir une nouvelle instance, dans certains cas.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre régulier Avatar de Fahelis
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2014
    Messages
    77
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2014
    Messages : 77
    Points : 87
    Points
    87
    Par défaut
    Merci pour ces explications supplémentaires
    Pensez au bouton quand votre problème est réglé afin de ne pas faire perdre leur temps aux gens qui essayent gentiment d'aider les autres

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

Discussions similaires

  1. Sécuriser une appli temps réel sous Swing
    Par Colargole dans le forum EDT/SwingWorker
    Réponses: 7
    Dernier message: 30/11/2009, 15h02
  2. bouger en temps réel
    Par lastrecrue dans le forum Développement 2D, 3D et Jeux
    Réponses: 6
    Dernier message: 18/05/2006, 08h38
  3. Voir requête éxécuté en temps réel ?
    Par [DreaMs] dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 08/01/2004, 14h52
  4. cubes temps réel en ROLAP
    Par Guizz dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 09/07/2003, 16h36
  5. Durée d'un traitement temps réel
    Par Almex dans le forum C
    Réponses: 5
    Dernier message: 29/03/2003, 14h15

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