Forum Clubic

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 )

http://img65.imageshack.us/img65/5742/35954172cx2.jpg

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 [B]repaint/B 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 )

http://img179.imageshack.us/img179/2679/67952729pl1.jpg
http://img179.imageshack.us/img179/67952729pl1.jpg/1/w441.png

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.[B]revalidate/B’ ou ‘panneau.[B]validate/B’ 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 :-o ) 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.
Edité le 03/02/2009 à 04:27

j’ai déjà eu des problèmes similaires mais sur des progs nettement moins complexes.

Essaie en rafraichissant carrément la jframe avec la méthode update( Graphics g);

ça devrait être du genre.

jframePlateau.update( jframePlateau.getGraphics );

à tester. :slight_smile:

bon courage quand même.

Du nouveau… !

Finalement, j’ai suivi le conseil d’une personne sur un autre fofo, et ai opté pour un modèle événementiel au lieu de mon ancien modèle “synchronisationnel foireux”… Et… Ca marche !

Après, j’ai quand même voulu re-essayer avec mon ancien modèle…
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 [B]removeAll/B 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-)
Merci beaucoup quand même a Jiheme44 pour son aide ; -)
et surement à une prochaine sur ce forum : -) !

NonoMoreno !

Ce n’est pas forcément une bonne idée de faire des sleep() quand tu joue avec l’interface graphique, qui pour le coup n’est qu’une seule thread qui lance tes événements… (genre une boucle infinie)

En effet Sans-Nom, j’ai suivi des conseils et c’est pour cela que j’ai opté pour un modèle événementiel.
Plus de boucle, plus de barrière… Et j’ai bien fait le distinguo entre le processus principal ( utilisateur ) et le processus graphique ( l’ETD ).
Et ca roule très bien maintenant. Merci quand même pour le conseil : -)