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

AWT/Swing Java Discussion :

Probleme illegalMonitorStateException avec un notify()


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Par défaut Probleme illegalMonitorStateException avec un notify()
    Bonjour,

    Je dois faire un jeu au tour à tour, tout s'affiche bien, mais pour actualiser à chaque tour, j'utilise la fonction update, mon code est sous cette forme:

    J'ai une classe Fenetre qui extends JFrame -->je recois donc mon objet graphique Fenetre f
    et la je modifie mes JLabel avec les getters et setText(), jusque la tout va bien.
    Ensuite je fais un f.update(f.getGraphics()) et la en fait ma raffraichi totalement, j'ai donc un clignotement de ma fenetre à chaque tour au lieu de seulement modifier les Label.

    J'ai donc trouver la fonction notify(), je la place dans un syncronized:

    synchronized (f.getGraphics()) {
    f.getGraphics().notify();
    }
    et la j'ai quand meme en retour un IllegalMonitorStateException et mon interface freeze..
    Quelqu'un voit-il pourquoi?

    Merci

  2. #2
    Expert confirmé
    Avatar de sinok
    Profil pro
    Inscrit en
    Août 2004
    Messages
    8 765
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Par défaut
    Pourquoi ne pas utiliser simplement un repaint?

    En swing tu ne dois normalement pas touche au getGraphics et update qui sont des mécanismes AWT à la base.

  3. #3
    Membre expérimenté
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    synchronized (f.getGraphics()) {
    	f.getGraphics().notify();
    }
    Problème n°1 : l’appel à JFrame.getGraphics, contrairement à ce que son nom peut suggérer, crée un nouveau Graphics à chaque appel. La synchronisation et la notification se faisant sur deux instances différentes, tu te prends un IllegalMonitorStateException.

    Problème n°2 : la méthode Object.notify est une primitive de synchronisation qui "réveille" les threads en attente (Object.wait) sur l’instance notifiée. Ça n’a aucun rapport ni aucune utilité dans le cadre des IHM. Si tu veux informer Swing qu’un composant doit être redessiné (de manière asynchrone d’ailleurs), il faut utiliser Component.repaint.

    Problème n°3 : modifier le modèle d’un JLabel via un appel à setText provoque déjà un appel à repaint. Ça ne sert donc à rien d’en refaire un.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    f.update(f.getGraphics())
    cf. la remarque de sinok. Sauf utilisation avancée de Swing ou le rendu est dirigé "manuellement", tu n’as jamais à appeler ce genre de méthode. Tu dois simplement construire une IHM sous forme d’une arborescence de composants, enregistrer des écouteurs qui la modifieront sur évènement et rendre le tout visible. C’est tout.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Par défaut
    Bonjour,

    en effet je pensais bien que seulement les setText() des JLabel suffisaient pour actualiser l'écran, mais pas cette fois et je ne sais pas pourquoi.. c'est pour cela que j'ai fait appel à update()...


    f.getTauxSoleil().setText(String.valueOf(c.getGame().getLight()) + "%");
    f.getTauxVent().setText(String.valueOf(c.getGame().getWind()) + "%");
    f.getTauxPluie().setText(String.valueOf(c.getGame().getWater()) + "%");

    Voici un exemple de mon code, mais si je ne place pas le f.update() rien ne se passe tant qu'on est pas arrivé au dernier tour, arrivé la il raffraichi bien et toutes les infos sont juste pour le dernier tour :s

    PS: je viens de tester avec des repaint() et ca ne bouge pas..

  5. #5
    Membre expérimenté
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Par défaut
    Le problème ne réside pas dans les trois lignes que tu donnes, mais très probablement dans ton mécanisme de changement de tour. À vue de nez, je suspecte une utilisation bloquante de l’EDT de Swing. Il faudrait cependant nous fournir plus de code sur cette partie pour pouvoir trancher.

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2013
    Messages : 4
    Par défaut
    Voici ma fonction qui update mes valeurs tour à tour:

    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
     public void updateFen(Fenetre f, Controleur c, CompterBatiment cb) {
     
            //MISE A JOUR NOMBRE TOUR
            f.getTour().setText(Integer.toString(c.getGame().getTurn()));
     
            //Si on n'a pas encore perdu
            if (c.isDefaite() == false) {
     
                //MISE A JOUR DONNEE METEO
             f.getTauxSoleil().setText(String.valueOf(c.getGame().getLight())+"%");
             f.getTauxVent().setText(String.valueOf(c.getGame().getWind()) +"%");
             f.getTauxPluie().setText(String.valueOf(c.getGame().getWater())+"%");
     
    //Mise à jour des info bâtiments
    f.getIndicationNucleaire().setText(String.valueOf(cb.getCompteur_nuclear()));
                f.getIndicationEolienne().setText(String.valueOf(cb.getCompteur_wind()));
                f.getIndicationSolaire().setText(String.valueOf(cb.getCompteur_solar()));
                f.getIndicationHydraulique().setText(String.valueOf(cb.getCompteur_water());
                f.getIndicationCharbon().setText(String.valueOf(cb.getCompteur_charbon()));
     
    }
    La classe Fenêtre qui est dans le tube est un extends de JFrame et dans laquelle il y a tout mes JLabel et getter

    la fonction d'update ce fait dans une boucle while qui tourne tant que le jeu continu..

    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
    while (c.getGame().getState() == GameStateEnum.RUNNING) {
     
                    //Trouver mon Player
                    for (int i = 0; i < c.getGame().getPlayers().size(); i++) {
                        if (c.getGame().getPlayers().get(i).getName().equals(c.getPseudo())) {
                            c.setMoi(c.getGame().getPlayers().get(i));
                        }
                    }
     
                    //Si on est mort, on bloque l'enregistrement de l'argent disponible dans l'ArrayList concernée
                    if (c.getMoi().getState() == PlayerStateEnum.DEAD) {
                        dead = true;
                    }
                    //On stocke les valeurs de cash, d'énergie need et available
                    if (dead == false) {
                        c.getArray_argent().add(c.getMoi().getCash());
                        c.getArray_energie_need().add(c.getMoi().getPowerNeed());
                        c.getArray_energie_available().add(c.getMoi().getPowerAvailable());
                    }
     
                    //Run de la partie qui retourne la partie ensuite et donc l'état du jeu (en cours, fini..)
                    c.setGame(r.run(c, f, cb, this, ecr));
                }
    c'est dans ce run qu'on appelle updateFen():

    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
    public Game run(Controleur c, Fenetre f, CompterBatiment cb, InitialiserLeJeu init, EcrireRapport ecr) {
     
            // display some stufs
            System.out.println("Play turn #" + c.getGame().getTurn());
     
            //Choisir un ordre
            IA ia = new IA();
            Order ordre;
            try {
                switch (c.getChoix_IA()) {
                    case 1:
                        ordre = ia.fuck_eco(c, init, ecr);
                        //Donner un ordre
                        c.setGame(c.getClient().giveOrder(ordre));
                        //Compte le nb de bâtiment
                        cb.compterBat(c);
     
                        break;
                    case 2:
                        ordre = ia.Survival(c, init, ecr);
                        //Donner un ordre
                        c.setGame(c.getClient().giveOrder(ordre));
                        cb.compterBat(c);
                        break;
                    case 3:
                        ordre = ia.love_eco(c, init, ecr);
                        //Donner un ordre
                        c.setGame(c.getClient().giveOrder(ordre));
                        cb.compterBat(c);
                        break;
                }
            } catch (IOException | JAXBException | InterruptedException | ClientException ex) {
                System.out.println("Erreur au niveau du setGame dans le Run");
            }
     
            //On update l'écran
            UpdateFenetre uf = new UpdateFenetre();
            uf.updateFen(f, c, cb);
     
            //On réinitialise les compteurs d'usines pour un nouveau tour de jeu
            cb.reinitialiserCompteur();
            return c.getGame();
        }
    Voila voila, ça fait beaucoup de code lâché comme ça, mais je ne peux pas mieux mettre dans le contexte :s

    Merci beaucoup au passage de proposer des choses!

  7. #7
    Membre expérimenté
    Avatar de Chatanga
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    211
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 211
    Par défaut
    Ce qui m’intéresserait, c’est ton code entre l’appel à ta fonction main et le moment où tu arrives à la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while (c.getGame().getState() == GameStateEnum.RUNNING) {
    Quelque ce soit ce dernier, tu as de toute manière un problème :
    • ou bien tu réalises ton while dans l’EDT et ça n’a pas de sens car tous les tours s’enchaînent sans redonner la main à ton IHM qui est donc bloquée entre-temps ;
    • ou bien tu réalises ton while dans un autre thread et tu ne respectes pas la contrainte qui consiste à mettre à jour l’IHM dans l’EDT.


    Par exemple, voici un bout d’implémentation simple (tout se fait dans l’EDT) qui fonctionnerait (notes la disparition du while).

    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
    public class Game {
     
    	public static void main(String[] arguments) {
     
    		Controleur c = null;
    		Fenetre f = null;
    		CompterBatiment cb = null;
    		InitialiserLeJeu init = null;
    		EcrireRapport ecr = null;
     
    		final Game game = new Game(c, f, cb, init, ecr);
     
    		/*
    		 * Avec un timer Swing, le thread de Swing (EDT = Event Dispatch Thread)
    		 * appellera régulièrement (toutes les 1000 millisecondes ici) l'action
    		 * de passage du tour.
    		 */
    		new javax.swing.Timer(1000, new ActionListener() {
    			public void actionPerformed(ActionEvent event) {
    				if (!game.runTurn()) {
    					((javax.swing.Timer) event.getSource()).stop();
    				}
    			}
    		}).start();
     
    		/*
    		 * On peut aussi imaginer que ça se fasse plutôt par l'appui manuel sur
    		 * un bouton.
    		 */
    		f.getNextTurnButton().addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent event) {
    				if (!game.runTurn()) {
    					((JButton) event.getSource()).setEnabled(false);
    				}
    			}
    		});
     
    		f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    		f.setVisible(true);
    	}
     
    	private boolean runTurn() {
     
    		// while (c.getGame().getState() == GameStateEnum.RUNNING) {
     
    		// Trouver mon Player
    		for (int i = 0; i < c.getGame().getPlayers().size(); i++) {
    			if (c.getGame().getPlayers().get(i).getName().equals(c.getPseudo())) {
    				c.setMoi(c.getGame().getPlayers().get(i));
    			}
    		}
     
    		// Si on est mort, on bloque l'enregistrement de l'argent disponible
    		// dans l'ArrayList concernée
    		if (c.getMoi().getState() == PlayerStateEnum.DEAD) {
    			dead = true;
    		}
     
    		// On stocke les valeurs de cash, d'énergie need et available
    		if (dead == false) {
    			c.getArray_argent().add(c.getMoi().getCash());
    			c.getArray_energie_need().add(c.getMoi().getPowerNeed());
    			c.getArray_energie_available().add(c.getMoi().getPowerAvailable());
    		}
     
    		// Run de la partie qui retourne la partie ensuite et donc l'état du jeu
    		// (en cours, fini..)
    		c.setGame(r.runIA(c, f, cb, this, ecr));
     
    		// }
     
    		// On continue ?
    		return c.getGame().getState() == GameStateEnum.RUNNING;
    	}
    }

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

Discussions similaires

  1. [String] Probleme incomprehensible avec split
    Par scorpiwolf dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 20/07/2004, 21h21
  2. [JTextAera][JScrollPane]Probleme mineur avec l'ascenseur
    Par Voxdei dans le forum Composants
    Réponses: 2
    Dernier message: 18/07/2004, 09h52
  3. [VB.NET] - Probleme Label avec Database
    Par codez dans le forum ASP.NET
    Réponses: 4
    Dernier message: 03/06/2004, 17h37
  4. probleme sql avec delphi
    Par lil_jam63 dans le forum Bases de données
    Réponses: 7
    Dernier message: 25/02/2004, 04h32
  5. probleme GRAVE avec directx 9
    Par l'arbre en plastique dans le forum DirectX
    Réponses: 3
    Dernier message: 02/09/2003, 23h59

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