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

Agents de placement/Fenêtres Java Discussion :

Problème d'affichage de JPanel (et de synchronisation?)


Sujet :

Agents de placement/Fenêtres Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 7
    Par défaut Problème d'affichage de JPanel (et de synchronisation?)
    Tout d'abord, Bonjour / Bonsoir à tous !
    Et je remercie d'avance ceux qui auront le courage de lire jusqu'en bas et de tenter de m'aider : -)

    ...

    Je suis en deuxième année d'IUT Informatique (à Montpellier), et ai pour projet de fin de semestre
    le développement en Java d'un jeu Othello implantant l'algorithme min/max pour l'Intelligence Artificielle.

    Si certains ne connaissent pas ce jeu, qui est très simple à comprendre,
    voici un lien avec quelques explications ( moins d'une minute devrait vous suffir ^^ ) :
    => http://www.ffothello.org/jeu/regles.php

    Toute la structure d'une partie, c'est a dire le bon déroulement des tours de jeu, est en place.
    L'interface graphique est aussi en place : une JFrame avec un JPanel, rempli de JButton! ( 64 pour le plateau de jeu )
    => Le processus principal et la fenêtre sont éxécutés dans deux tâches différentes.


    Voici un screen de ma fenêtre lors du premier tour :
    ( en bleu les cases jouables )





    ...


    Pour une meilleure compréhension,
    je vous décris le déroulement d'un tour de jeu dans mon programme :


    ... 1- Tout d'abord, le programme calcule les cases étant jouables, et les affiche au joueur.
    ... ... => Envoi du nouveau plateau a afficher au panneau de la fenêtre.
    ... 2- Ensuite, il attend qu'un coup soit joué. ( il se bloque devant une CyclicBarrier, initialement à 2, et qu'il met 1. )
    ... 3- Une fois le coup joué, la barrière s'ouvre, le processus principal en récupère les coordonnées, et les inscris dans le plateau.
    ... 4- Une fonction détermine ensuite les cases "prises en sandwich" / "à retourner", et modifie le plateau.
    ... 5- Puis le programme affiche le nouveau plateau de jeu, avant de passer au tour suivant.
    ... ... => Nouvel envoi du nouveau plateau au panneau.


    Par "Envoi du nouveau plateau", j'appelle une méthode "affectation", qui est une sorte de second constructeur du panneau,
    et qui met à jour les données partagées par le panneau et la Partie, et fais un repaint() du panneau.
    => Dans ces données, il y a principalement le plateau, qui doit être réaffiché avec le repaint().
    ( ré-Affichage des 64 cases, qui sont des JButton )

    ...

    Mon problème est le suivant :

    - Lorsque c'est au premier tour, le processus principal calcule les coups jouables (pour le joueur blanc),
    les envoie au panneau qui se charge de les afficher, puis attend devant la barriere que le coup soit joué.
    ===> La réactualisation du panneau marche, comme vous pouvez le voir avec le screen. (affichage des cases jouables en bleu )

    - Dès que je clique sur une de ces cases jouables, celle ci se redessine avec la couleur du joueur, puis réveille le processus principal, et y envoie ses coordonnées. Le processus principal récupère ses coordonnées, les traite parfaitement... ( phases 3 et 4 )
    ==> Des test d'affichage en console montrent que le plateau est correctement à jour.

    - Mais, a la phase 5, à l'envoi de ce nouveau plateau, et malgré le repaint(), le panneau ne se réactualise pas...
    Et la fenetre affiche seulement l'ancien panneau (avec les cases jouables) et la case jouée qui s'est autoactualisée elle même.
    ( Hum... Je pense que certains vont commencer à se poser des questions sur mes méthodes de "repaintage" x-) )


    Plateau affiché après le clic sur la case que l'on souhaite jouer :
    ( la case noire prise en sandwich en [4][5] devrait être blanche, ce qu'elle est en console )





    ...

    Mon souhait est donc simple :
    => Arriver à réactualiser mon panneau, avec les nouvelles informations de fin de tour !


    Précisions:

    - Comme dit au début, j'utilise deux tâches différentes pour la Partie et la fenêtre, synchronisées avec une CyclicBarrier (init à 2).
    ==> Mais il y a peut être un foirage dans leur utilisation... ? :-/

    - Quand je ne donne pas les coordonnées des coups avec l'interface graphique ( j'écris pour chaque tour les coordonnées dans le code ),
    => Tout se passe parfaitement ! Par ex, si je stoppe ma boucle de jeu au tour n°7, le panneau m'affiche le plateau comme il devrait être.
    ===> Par contre, si j'essaie de mettre un 'Thread.sleep()' de deux secondes a la fin de chaque tour, cela replante identiquement.
    ( En gros, mon programme n'aime pas trop qu'on le perturbe un chouilla semble t'il ... )


    ...


    Voila donc en gros mon problème...
    Dont je ne sais s'il est graphique ou 'synchronisationnel', ou bien même peut être les deux, ou encore moulte autre chose... ! ( o_O )
    J'ai testé des 'panneau.revalidate()' ou 'panneau.validate()' dans ma méthode 'affectation()', mais rien de plus...

    Je sais que ce message est un beau paté, mais j'essaie d'être clair pour vous faciliter la chose.. ( ou pas ) Mais cela fait en deux jours facilement 15h que je bute sur ce problème, en tentant le peu de choses que mes modestes compétences me permettent, et arpentant the Internet a la recherche de quelque chose.. Et je n'ai pour l'instant obtenu qu'un bon, beau, gros, frais, fort, nature... Pwet :-/

    ...

    Pour le code source entier, si des généreux et courageux seraient tentés de s'y aventurer,
    je l'ai mis à disposition à dans un dossier à dézipper, en format "projet" de Eclipse. ( Juste à importer )
    => http://www.megaupload.com/fr/?d=1VP243BS

    Je suis complètement partisan du "débrouilles toi avec ta besogne, on va pas te faire ton logiciel non plus !",
    mais si cela peut vous permettre d'y voir plus clair dans le comment j'ai fait ma ... hum, alors et bien c'est avec plaisir : -)
    ( Le code est normalement "bien" commenté et lisible, vous devriez vous en sortir )

    ...

    Voila voila... Pouf, allez je vais stopper ce message là.
    Et remercie d'avance toutes personnes qui auront eu le courage d'arriver jusqu'ici, et qui essaieront de m'aider. : -)
    Je reste bien sûr au taquet réactif à quelconque question, ou demande de précisions !

    En vous souhaitant une Bonne fin de soirée, nuit, réveil !
    NonoMoreno.

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,



    Je pense qu'il faudrait que tu te plonges dans les concepts même de Swing, je te conseillerais un peu de lecture :




    J'ai parcouru rapidement ton code et j'ai remarqué ceci :

    • Swing est mono-tâche : tout ce qui touche à l'interface graphique doit être exécuté dans l'EDT (j'en reparlerais plus bas).
    • Pour un meilleur résultat, il serait souhaitable de ne faire le setVisible(true) qu'après avoir ajouté tous ses composants (bref à la fin).
    • Évites de charger les images dans les méthodes paintComponent() ou dans les listeners : cela peut être exécuté un très grand nombre de fois et c'est lourd... Ces méthodes devraient s'exécuter très rapidement. Il serait préférable de les instancier une fois pour toute (en static pour faire simple, ou via un mécanisme de cache pour quelque chose de plus élaboré).
    • Tu ne devrais pas utilisé de synchronisation entre ton thread et l'EDT : il ne faut surtout pas bloqué l'EDT ! Il faudrait revoir cela selon le principe événementielle
    • Ton "animation()" n'est pas correct, car tu modifies des composants graphiques depuis un thread différent de l'EDT. Il serait plus propre et plus simple de passer par un javax.swing.Timer :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      	// On crée un timer qui s'exécutera toutes les 500 ms
      	Timer timer = new Timer(500, new ActionListener() {
      		@Override
      		public void actionPerformed(ActionEvent e) {
      			// Ici on est dans l'EDT on peut modifier les composants
      		}
      	});
       
      	// On démarre le timer
      	timer.start();



    Tout ceci peut sembler anecdotique mais cela peut engendrer des problèmes difficilement compréhensible...



    Pour faire simple, plutôt que de passer par la synchronisation, tu devrais utiliser les événements. Il serait peut-être aussi utile de passer par un modèle représentant le plateur de jeu :
    • Tu as un modèle qui représente l'état de la partie, avec un mécanisme de listener pour signaler les changements (Comment créer son propre Listener ?). On pourrait avoir par exemple deux méthodes de listener : une qui signale le joueur qui doit jouer, et une autre qui signale les changements sur le plateau (une pièce a été posé, une pièce a été retourné, etc.)
    • Tu as un composant représentant ton plateau, qui s'enregistre en tant que listener auprès de ton modèle, et qui le consulte pour afficher les bonnes infos.
    • Lorsque le joueur joue, il modifie le modèle qui signalera le changement via les listeners.
    • Lorsque ton composant est averti que c'est au tour de l'ordi de jouer, il doit "désactiver" ses listeners afin que le joueur ne puisse plus poser de pions...
    • En plus de cela tu as un Listener qui représentera l'ordi : lorsqu'il apprend que c'est à lui de jouer, il lances un thread qui calculera la meilleure position, et une fois que c'est fini il indiquera son choix au modèle via l'EDT (avec SwingUtilities.invokeLater() ou un SwingWorker).
    • Et cela bouclera comme cela...


    L'EDT ne sera jamais bloqué : il se contentera d'afficher les données, de gérer les événements et les modifications du modèle...



    Bon courage...

    a++

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 7
    Par défaut
    Hello adiGuba !


    Et déjà, merci grandement pour l'attention porté à mon problème : -)

    Je viens de me "plonger" pendant plusieurs heures dans les concepts de Swing,
    avec notamment le rôle primordial de l'EDT, et ai essayé d'expérimenter les "invokeLater()" et compagnie..

    Et résultat : Et bien toujours pwet on va dire.
    Malgré que tes liens soient parfaits, car si j'arrivais à bien comprendre ces tutoriaux je pense que je me sortirais d'affaire...
    Mais c'est peu de choses que de dire que je n'y suis pas super bien arrivé :-/

    ...

    Ensuite, pour l'idée de faire de "l'événementiel" au lieu du "synchronisationnel", je pense avoir à peu près compris.. en théorie.
    Mais en pratique, je n'arrive pas bien a visualiser le contenu de mon thread Utilisateur.. :-/

    En fait, ce qui bloque je pense est de savoir ce que doit faire le thread Utilisateur lors de la phase "attente que le coup soit jouée",
    qui doit être désenclenchée graphiquement. Ou plutôt, je n'arrive pas à concevoir qu'il fasse autre chose que s'endormir ( pour ne pas gaspiller des ressources ).

    Enfin.. Pouf, voila.. On va dire que j'ai le cerveau en ébullition.
    Et ne sais moyen trop quoi faire..

    ...

    Pour résumer, j'ai bien compris que tout tes conseils allaient dans une optique de performance.
    Mais étant lundi soir, et ayant encore tout le morceau IA à me taper d'ici mercredi matin...
    Je pense qu'il faut rapidement que j'obtienne quelque chose qui marche, tant pis pour les performances... ( aie pas taper : -o )
    Sachant que j'ai déja passé pas mal de temps à concevoir ce modèle foireux, et que en refaire un autre, bin... :-/

    Donc en gros penses tu qu'avec mon modèle "synchronisationnellement foireux" je puisse y arriver?
    Et si oui as tu une idée ?


    P.S: Sachant que je commence dans une semaine un stage de 3 mois ou j'aurais normalement loisir à manger de la synchronisation en Java,
    je pense que je m'appuierais sur tout ce que tu m'as conseillé. Et a l'occasion, essaierais de revoir l'optimisation de mon programme à ce moment la.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 7
    Par défaut
    Du nouveau... !

    Finalement, j'ai suivi le conseil de adiGuba et ai opté pour le modèle événementiel !
    Et... Ca a marché !

    Après, j'ai aussi essayé mon ancien modèle "synchronisationnel foireux"...
    Et ca marche aussi maintenant !

    La raison...?

    ...

    => A chaque repaint(), mes nouveaux composants s'affichaient * en dessous * des anciens.
    ... ! ! ....

    ...


    Allez, j'importe java.util.zenToolkit et je n'essaie pas de comprendre...
    En oubliant la trentaine d'heure passée sur un problème qu'un simple removeAll() a résolu avant chaque repaint()...

    Donc voila. Maintenant je vais pouvoir attaquer mon IA, qui, soyons fou, j'espère sera prête pour ma soutenance demain x-)
    Encore un grand merci a adiGuba pour tout tes conseils et le temps passé sur mon cas,
    et surement à une prochaine sur ce forum : -) !

    NonoMoreno !

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

Discussions similaires

  1. Problème affichage Image Jpanel
    Par lerorodu51 dans le forum NetBeans
    Réponses: 17
    Dernier message: 10/06/2009, 19h43
  2. un problème avec l'affichage de JPanel
    Par maya123 dans le forum Débuter
    Réponses: 2
    Dernier message: 13/03/2009, 00h04
  3. Réponses: 3
    Dernier message: 07/07/2008, 23h03
  4. Problème d'affichage du contenu de JPanel
    Par Mic75 dans le forum AWT/Swing
    Réponses: 12
    Dernier message: 13/12/2007, 00h53
  5. Problème d'affichage surperposition de JPanel
    Par marcel72 dans le forum AWT/Swing
    Réponses: 11
    Dernier message: 17/07/2007, 16h47

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