Déplacer plusieurs cercles dans une JFrame

Résolu
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012 - 2 janv. 2012 à 03:28
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 - 5 janv. 2012 à 15:51
Bonjour.

J'ai une liste d'objets (des cercles) dans une JFrame. Je voudrai qu'ils se déplacent dans cette surface. Je sais comment en déplacer un, mais tous simultanément.

voilà la méthode principale que j'appelle dans mon main:
     public void create()
    { 
        monde.setSize(700, 635);
        monde.setPreferredSize(new Dimension(700, 650));
        monde.setBackground(Color.GRAY);
        monde.setLocationRelativeTo(null);
        monde.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //écouteur
       // monde.addMouseListener(null);
        
        un = new Univers(); 
        
        monde.setContentPane(un);

        monde.pack();
        monde.setVisible(true);
        go();
}



les objets que je crée. elfes, trolls et magiciens sont des arrayList
 @Override
    public void paintComponent(Graphics g)
    {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);
        g2d.fillRect(0, 0, 700, 450);
        
        int x, y;
        Color couleur;
        
        for(int j=0; j<elfes.size(); j++)
        {
            //on récupère les coordonnées
            x=elfes.get(j).getPosX();
            y=elfes.get(j).getPosY();
            couleur=elfes.get(j).getCouleur();
            g2d.setColor(couleur);
           // this.addMouseListener(null);
            g2d.fillOval(x, y, 10, 10);
        }

        for(int j=0; j<trolls.size(); j++)
        {
            x=trolls.get(j).getPosX();
            y=trolls.get(j).getPosY();
            couleur=trolls.get(j).getCouleur();
            g2d.setColor(couleur);
            g2d.fillOval(x, y, 10, 10);
        }

        for(int j=0; j<magiciens.size(); j++)
        {
            x=magiciens.get(j).getPosX();
            y=magiciens.get(j).getPosY();
            couleur=magiciens.get(j).getCouleur();
            g2d.setColor(couleur);
            g2d.fillOval(x, y, 10, 10);
        }       
    }
    


La méthode go() qui doit servir à déplacer les objets et sur laquelle je bloque!!

   private void go()
    {
     //   un.repaint();
        ArrayList<Elfe> e = un.elfes;
        
        for (int j=0; j<e.size(); j++)
        {
          //Les coordonnées de départ de notre rond
        int x e.get(j).getPosX(), y e.get(j).getPosY();
        //Le booléen pour savoir si on recule ou non sur l'axe X
        boolean backX = false;
        //Le booléen pour savoir si on recule ou non sur l'axe Y
        boolean backY = false;

        while(true)
        {
            //Si la coordonnée x est inférieure à 1, on avance
            if(x < 1)backX = false;
            //Si la coordonnée x est supérieure à la taille du Panneau
            //moins la taille du rond, on recule
            if(x > 650)backX = true;

            //idem pour l'axe Y
            if(y < 1)backY = false;
            if(y > 600)backY = true;

            //Si on avance, on incrémente la coordonnée
            if(!backX)
                e.get(j).setPosX(++x);
            //Sinon, on décrémente
            else
                e.get(j).setPosX(--x);

            //Idem pour l'axe Y
            if(!backY)
                e.get(j).setPosY(++y);
            else
                e.get(j).setPosY(--y);

            //On redessine notre Panneau
            un.repaint();

            try 
            {
                Thread.sleep(3);
            } 
            catch (InterruptedException ex) 
            {
                    // TODO Auto-generated catch block
                ex.printStackTrace();
            }
        }   //Fin while
        }
    }

Je ne sais donc pas comment faire pour déplacer tous lesobjets que j'ai dessinés dans paintCompoment.

J'espère qu'on pourra m'aider; ça fait des heures que je cherche à le faire marcher.

Bonne année!!

14 réponses

cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
2 janv. 2012 à 07:58
Bonjour,

C'est vrai qu'implémenté de cette facon, c'est assez difficile de gérer plusieurs déplacement, bien que ce soit possible en passant toutes les coordonnées (voire une arraylist à la méthode go, ce qui n'est pas génial).

Je te conseil donc d'utiliser proprement les Threads. En gros un Thread est un processus (ou presque). Il te permettra de créer le code qui déplacera un cercle et tu pourras lancer plusieurs threads qui te permettrons de déplacer plusieurs cercles.

Alors, comment faire ?

Premièrement, il ne faut pas placer tes cercles dans la méthode paint mais créer un JPanel cercle de cette facon ;

public class Cercle extends JPanel {

public Cercle(){
super();
}

@Override
public void paintComponent(Graphics g){
g.setColor(Color.RED);
g.fillOval(0, 0, getWidth(), getHeight());
}

}


Et ensuite, pour le placer sur le panel qui le contient :
JPanel panel = new JPanel();
panel.setLayout(null);
Cercle c = new Cercle();
c.setBounds(x, y, width, height);
panel.add(c);


Voilà pour le début, passons aux Thread. Tout d'abord, il faut le créer :

public class AnimateurCercle extends Thread {

/** Le cercle à déplacer */
private Cercle cercle;

public AnimateurCercle(Cercle cercle){
this.cercle=cercle;
}

/**
 * Cette méthode définit le traitement à effectuer
 * Ici, tu définis donc le déplacement du cercle passé en paramètre
 */
@Override
public void run() {
while(true){
//En gros, c'est ce que fait ta méthode go()
}
}

}


Enfin, il faut appeler ton thread sur un cercle.

Pour celà :
JPanel panel = new JPanel();
panel.setLayout(null);
Cercle c1 = new Cercle();
AnimateurCercle a1 = new AnimateurCercle(c1);
c1.setBounds(0, 0, 60, 60);
Cercle c2 = new Cercle();
AnimateurCercle a2 = new AnimateurCercle(c2);
c2.setBounds(0, 0, 60, 60);
panel.add(c1);
panel.add(c2);
a1.start();
a2.start();
3
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
2 janv. 2012 à 08:02
Une petite explication complémentaire : pourquoi utiliser une méthode run() à la place de go() ?

Tu remarqueras que la méthode run n'est jamais appelée dans le code. C'est parce que c'est une méthode qui lance le traitement dans le thread courant et donc, quand elle est lancée, le programme attend que cette méthode soit terminée pour lancer les instructions suivantes. En gros, tu ne peux pas en lancer deux simultanément.

En revanche, la méthode start de thread appelle la méthode run dans un nouveau thread, tu peux donc en lancer plusieurs simultanément.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
2 janv. 2012 à 08:03
Une dernière chose, je n'ai pas testé le code que je t'ai donné et je l'ai écris directement dans la fenêtre d'édition sur le forum, il y a donc peut être quelques fautes de frappes.
0
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012
2 janv. 2012 à 13:54
Merci Julien39.

je vais essayer et je te tiens au courant.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012
3 janv. 2012 à 03:05
Je suis débutante en java et je n'avais pas pensé au thread, reste à savoir l'implémenter.

J'ai donc suivi tes conseils et fait pareils, mais il n'y a aucun mouvement.


Voilà ce que j'ai fait:

Mon cercle (Elfe)

public class Elfe extends Individus
{
    
    private Utilitaire u = new Utilitaire();
        
    public Elfe(int x, int y, String nom)
    {
        super();
        
        this.posX = x;
        this.posY = y;
        this.setType("ELFE");
        this.vol = u.randomChiffre(0, 100); 
        this.setPatience(u.randomChiffre(0, 100));
        this.setAgressivite(u.randomChiffre(0, 100));
        this.setNegociation(u.randomChiffre(0, 100));
        this.setCapacite(u.randomChiffre(0, 100));
        this.couleur = Color.WHITE;
        this.setName(nom);
    }
        
    @Override
    public void paintComponent(Graphics g)
    {
    //    g.setColor(Color.YELLOW);
    //    g.fillRect(10, 10, 700, 700);
        
        g.setColor(couleur);
        g.fillOval(0, 0, getWidth(), getHeight());
    }
}


l'animation
public class ThreadAnimation extends Thread
    {
        private Individus i;

        public ThreadAnimation(Individus i)
        {
            this.i = i;
        }
        
        @Override
        public void run() 
        {
            int x = i.getPosX();
            int y = i.getPosY();
  
            while(true)
            {
                System.out.println("\n"+x);
                
                if(x < 1)backX = false;
                // j'ai préféré mettre les coordonnées de la fenêtre en dur
                if(x > 700)backX = true;               
                if(y < 1)backY = false;
                if(y > 650)backY = true;
                if(!backX)i.setPosX(++x);
                else i.setPosX(--x);
                if(!backY) i.setPosY(++y);
                else i.setPosY(--y);

      // le repaint servirait à redessinner un rectangle sur la                      //surface pour afficher l'objet à sa nouvelle position. Mais ça ne marche pas
                i.repaint();

                try 
                {
                    Thread.sleep(3);
                } 
                catch (InterruptedException e) 
                {
                // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
      }
}


Et la fenetre principale
  public void create()
    {               
        monde.setSize(700, 650);
        monde.setPreferredSize(new Dimension(700, 650));
        monde.setBackground(Color.GRAY);
        monde.setLocationRelativeTo(null);
        monde.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // initialisation du panneau affichant les stats
        fenetre2();

        for(int j=0; j<100; j++)
        {
            //génération aléatoire des coordonnées de départ du cercle
            int x = u.randomChiffre(0, 670);
            int y = u.randomChiffre(0, 600);
            
            Elfe e = new Elfe(x, y, "ELFE"+j);
            elfes.add(e);
            
            ThreadAnimation th = new ThreadAnimation(e);
            e.setBounds(x, y, 10, 10);
            contenu.setLayout(null);
            contenu.setBackground(Color.CYAN);        
            contenu.add(e);
            
            th.start();
        }
        
        monde.add(contenu, BorderLayout.CENTER);
        monde.pack();
        monde.setVisible(true);

    }   // Fin create()
          


Je pense que ça vient de repaint, mais je ne suis pas sure..
0
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012
3 janv. 2012 à 03:08
Dans la console,
System.out.println("\n"+x);

affiche bien les nouvelles coordonnées
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
3 janv. 2012 à 07:58
Bonjour,

Déjà, tu peux sortir "contenu.setLayout(null);" de la boucle, tu n'as besoin que de le faire une fois.

Ensuite, tu fais un i.repaint() et ce n'est pas ce qu'il faut faire. Je m'explique : quand tu fais i.repaint() alors la méthode paint est appelée sur le panel i uniquement, le panel est donc redessiné à l'endroit ou il se trouve, ce n'est pas i qu'il faut redessiner mais son conteneur.

Alors, pour réussir à faire le bon repaint, tu peux placer le conteneur en paramètre du constructeur de ton thread (le conteneur c'est contenu) et au lieu de i.repaint(), fais contenu.repaint().


Il y avait d'ailleurs une solution astucieuse qui te permettait également de faire celà en créant le thread dans la méthode paint(), mais en développement objet, on préfère faire ce que je t'ai dis.
0
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012
3 janv. 2012 à 18:32
J'avais essayé cette méthode, mais en vain.
J'ai même essayé à la place de repaint:
//suppression de l'objet avant changement de coordonnées
contenu.remove(i);
//avec les nouvelles coordonnées
contenu.add(i);
0
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012
3 janv. 2012 à 19:08
Je pense que le but de redessiner les cercles, et pas le panel sinon ça écrasera à chaque fois les autres objets.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
4 janv. 2012 à 07:53
Non, ca n'écrasera rien du tout.

Attend, je regarde à nouveau ton code.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
4 janv. 2012 à 08:01
Franchement, je ne comprend pas ce qui ne fonctionne pas. Si dans la console l'affichage est bon, ca devrait fonctionner.

As tu essayé d'afficher i.getPosX(); et i.getX()?

Est ce que tu gères bien l'affichage des positions de tes composants. Il ne suffit pas de modifier posX pour que ton Panel soit déplacer, il faut également redéfinir l'emplacement X avec un setLocation ou un setBounds chaque fois que posX est modifié. L'as tu fait ? Je dirais que non.

La solution est : sur ton Panel Individu, dans la méthode setPosX et et PosY, appelles un setLocation ou un setBounds qui te permettra également de modifier les coordonnées de l'objet dans son conteneur.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
5 janv. 2012 à 08:02
Ou en es tu ? Ca marche ?
0
honeyfree Messages postés 8 Date d'inscription mercredi 23 mai 2007 Statut Membre Dernière intervention 5 janvier 2012
5 janv. 2012 à 14:27
ça marche, mais avec la première version que j'ai postée (avec les objets dans le paintComponent).
J'ai donc retenu ton idée de thread.
J'ai créé une classe ThreadAnimation dont le run contient le code de déplacement. J'envoie un arraylist à la méthode go, et pour chaque objet de la liste, je crée un thread.

L'implémentation n'est pas terrible, mais comme c'est ma première appli java, je continue avec ça. Ma façon de coder devrait améliorer au fur et à mesure du temps.

Je te remercie pour tes interventions. Tes explications étaient claires et m'ont bien aidée.
0
cs_Julien39 Messages postés 6414 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 29 juillet 2020 371
5 janv. 2012 à 15:51
C'est tout de même bizarre que ca n'ait pas marché avec les JPanel.

Enfin bon, si le résultat te convient, ca me va aussi.

a+
0
Rejoignez-nous