Déplacer plusieurs cercles dans une JFrame [Résolu]

honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 2 janv. 2012 à 03:28 - Dernière réponse : cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention
- 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!!
Afficher la suite 

14 réponses

Répondre au sujet
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 2 janv. 2012 à 07:58
+3
Utile
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();
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de cs_Julien39
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 2 janv. 2012 à 08:02
0
Utile
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.
Commenter la réponse de cs_Julien39
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 2 janv. 2012 à 08:03
0
Utile
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.
Commenter la réponse de cs_Julien39
honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 2 janv. 2012 à 13:54
0
Utile
Merci Julien39.

je vais essayer et je te tiens au courant.
Commenter la réponse de honeyfree
honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 3 janv. 2012 à 03:05
0
Utile
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..
Commenter la réponse de honeyfree
honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 3 janv. 2012 à 03:08
0
Utile
Dans la console,
System.out.println("\n"+x);

affiche bien les nouvelles coordonnées
Commenter la réponse de honeyfree
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 3 janv. 2012 à 07:58
0
Utile
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.
Commenter la réponse de cs_Julien39
honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 3 janv. 2012 à 18:32
0
Utile
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);
Commenter la réponse de honeyfree
honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 3 janv. 2012 à 19:08
0
Utile
Je pense que le but de redessiner les cercles, et pas le panel sinon ça écrasera à chaque fois les autres objets.
Commenter la réponse de honeyfree
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 4 janv. 2012 à 07:53
0
Utile
Non, ca n'écrasera rien du tout.

Attend, je regarde à nouveau ton code.
Commenter la réponse de cs_Julien39
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 4 janv. 2012 à 08:01
0
Utile
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.
Commenter la réponse de cs_Julien39
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 5 janv. 2012 à 08:02
0
Utile
Ou en es tu ? Ca marche ?
Commenter la réponse de cs_Julien39
honeyfree 8 Messages postés mercredi 23 mai 2007Date d'inscription 5 janvier 2012 Dernière intervention - 5 janv. 2012 à 14:27
0
Utile
ç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.
Commenter la réponse de honeyfree
cs_Julien39 6449 Messages postés mardi 8 mars 2005Date d'inscription 15 mars 2018 Dernière intervention - 5 janv. 2012 à 15:51
0
Utile
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+
Commenter la réponse de cs_Julien39

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.