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 :

Thread + crash sur rafraîchissement table : model pas encore mis à jour?


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de seiryujay
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 950
    Par défaut [Maj]Thread+crash table:model pas mis à jour? => ListSelectionListener et JTreeTable
    Salut!

    J'ai un petit souci. En fait, j'utilise le composant JTreeTable disponible ici. Jusqu'à présent, je n'avais aucun problème, mais depuis que j'ai ajouté des threads pour exécuter les gros traitements, j'ai des crashes (pas critiques, mais embêtants) survenant sur la supression de noeuds. Il s'agit de crashes sur le repaint(), avec notamment des ArrayOutOfBoundException dû au fait que mon modèle ne doit pas être totalement à jour.

    J'aimerai savoir comment me débrouiller pour être sûr que mon modèle est toujours à jour, et que ma JTreeTable a été prévenue des changements intervenus dans mon modèle.

    Merci d'avance.

  2. #2
    Membre Expert
    Avatar de afrikha
    Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    1 600
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2005
    Messages : 1 600
    Par défaut
    Salut,
    je ne suis pas sùr d'avoir bien compris ton problème...

    Citation Envoyé par seiryujay
    mais depuis que j'ai ajouté des threads pour exécuter les gros traitements, j'ai des crashes (pas critiques, mais embêtants) survenant sur la supression de noeuds.
    La mise à jour de l'interface graphique doit se faire depuis l'EDT. Tu peux utiliser SwingUtilities.invokeLater ou bien SwingUtilities.invokeAndWait .
    J'aimerai savoir comment me débrouiller pour être sûr que mon modèle est toujours à jour,
    Là je ne comprends pas trop...
    et que ma JTreeTable a été prévenue des changements intervenus dans mon modèle.
    Tu dois avoir dans ton modèle une méthode du style fireContentChanged , non ?


    Mes publications
    Lisez
    Les régles du forum
    Pensez au bouton

  3. #3
    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,


    Il faut que toutes les modifications sur ton modèle soit effectué dans l'EDT.
    Si tu modifies le modèle depuis un autre thread, tu peux te retrouver dans un cas du style :
    • L'EDT est en train de redessiner la table (qui comporte par exemple 20 éléments).
    • Ton autre thread reprend la main et supprime un élément.
    • L'EDT tente d'accéder au 20ième élément qui n'est plus présent --> ArrayOutOfBoundException

    La classe SwingWorker pourrait t'être utile

    a++

  4. #4
    Membre éclairé
    Avatar de seiryujay
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 950
    Par défaut
    Citation Envoyé par adiGuba
    Salut,


    Il faut que toutes les modifications sur ton modèle soit effectué dans l'EDT.
    Si tu modifies le modèle depuis un autre thread, tu peux te retrouver dans un cas du style :
    • L'EDT est en train de redessiner la table (qui comporte par exemple 20 éléments).
    • Ton autre thread reprend la main et supprime un élément.
    • L'EDT tente d'accéder au 20ième élément qui n'est plus présent --> ArrayOutOfBoundException

    La classe SwingWorker pourrait t'être utile

    a++
    C'est exactement ce qui m'arrive je pense.
    Je vais jeter un oeil à cette classe...
    Par contre, je travaille sous JRE 1.4.2, donc cette classe ne faisait pas partie de l'API et si une meilleure gestion de mon code peut me permettre de contourner le problème, je préfère autant faire comme ça.

    Donc petite question :
    Ma JTreeTable sert à lister et à donner des informations sur des formes géométriques.
    Les feuilles correspondent à des formes simples, et les noeuds correspondent à des groupes de formes. En fait, je regroupe certaines formes suivant des critères liés à la surface, la longueur, etc des formes simples.
    Du coup, si je supprime une forme simple, il se peut qu'un groupe soit complétement détruit, et divisé en plusieurs nouveaux groupes ou formes simples, si les critères de regroupement ne sont pas respectés.
    Ca c'est le principe.

    Donc sur la suppression d'une feuille, je dois réappliquer le calcul de regroupement sur les formes contenues dans le groupe modifié. Dans ce calcul, je recrée les nouveaux groupes qui seront ensuite affichés dans ma JTreeTable => modification du model.
    Et comme ça prend du temps, j'ai fait ça dans un thread.

    Il suffit juste que je remplace ce thread par un invokeLater() pour que je n'ai plus ces crashes?
    Je vais tester, mais si vous pouvez me le confirmer...

    Merci d'avance!

  5. #5
    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
    Citation Envoyé par seiryujay
    Il suffit juste que je remplace ce thread par un invokeLater() pour que je n'ai plus ces crashes?
    Je vais tester, mais si vous pouvez me le confirmer...
    Non si tu remplaces tout le thread par un invokeLater() cela n'a plus aucun intérêt car tout ton traitement sera exécuté dans l'EDT et donc cela bloquera l'affichage.

    Tu dois juste utiliser invokeLater() pour modifier le modèle.
    Ainsi ton thread se charge de tous les calculs, et lorsque il a besoin de modifier le modèle il utilisera invokeLater() pour le faire (ou invokeAndWait() s'il a besoin d'attendre la fin du traitement).

    Le plus simple serait de te faire une série de méthode qui effecuerons la tâche dans l'EDT, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        public void removeFromModel(final int index) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    monModel.remove(index);
                }
            });
        }
    a++

  6. #6
    Membre éclairé
    Avatar de seiryujay
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 950
    Par défaut
    Citation Envoyé par adiGuba
    Non si tu remplaces tout le thread par un invokeLater() cela n'a plus aucun intérêt car tout ton traitement sera exécuté dans l'EDT et donc cela bloquera l'affichage.

    Tu dois juste utiliser invokeLater() pour modifier le modèle.
    Ainsi ton thread se charge de tous les calculs, et lorsque il a besoin de modifier le modèle il utilisera invokeLater() pour le faire (ou invokeAndWait() s'il a besoin d'attendre la fin du traitement).

    Le plus simple serait de te faire une série de méthode qui effecuerons la tâche dans l'EDT, par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        public void removeFromModel(final int index) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    monModel.remove(index);
                }
            });
        }
    a++
    Ok, je vais essayer de faire ça.
    Faut que je me replonge dans ces mécanismes...

    Merci!
    PS : je laisse le sujet ouvert au cas où...

  7. #7
    Membre éclairé
    Avatar de seiryujay
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 950
    Par défaut
    Me revoilà avec mon problème...

    Alors moi tout naïf que je suis, je m'étais dit : "temps de calcul important => on va mettre une progress bar et faire les traitements longs dans un thread".
    On me dit "modification du model de ma table => à faire dans l'EDT".

    Moi tout content, je me fais.
    Mais une fois que c'est fait, je me rend compte d'un truc : ce qui prend du temps, c'est la mise à jour du model!

    Je m'explique :
    Si je fais du undo après une suppression d'un noeud, je recrée le noeud supprimé, ainsi que TOUS SES FILS.
    Or dans le cas d'un grand nombre de fils, ça prend du temps. Et ça c'est de la modification du modeln donc à faire dans l'EDT, non?

    Je poste 2 ou 3 bouts de code qui expliquent le schmilblick :

    1) Méthode de rechargement des noeuds fils (présente dans le model) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    /**
     * Recharge les fils du noeud <code>node</code>.
     */
    public void reloadChildren(Object node) {
    	DefectNode dn = (DefectNode) node;
     
    	synchronized (this) {
    		reloadCount++;
    	}
    	dn.resetSize();
    	new DefectNodeLoader((DefectNode) node).load();
    }
    2) Constructeur de DefectNodeLoader appelé juste au-dessus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    DefectNodeLoader(DefectNode node) {
    	this.node = node;
    	node.setChildren(node.createChildren(defectMS), true);
    	node.setTotalSizeValid(false);
    }
    3) Méthode createChildren() (qui crée les neuds fils) appelée juste au-dessus :
    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
     
    /**
     * Loads the children of the receiver.
     */
    protected DefectNode[] createChildren(MergeSort sorter) {
    	DefectNode[] retArray = null;
     
    	try {
    		Defect[] defects = defect.getSubDefectsArray();
    		if (defects != null) {
    			if (sorter != null) {
    				sorter.sort(defects);
    			}
    			retArray = new DefectNode[defects.length];
     
    			for (int i=0; i<defects.length; i++) {
    				Defect childDefect = defects[i];
    				retArray[i] = new DefectNode(this, childDefect);
    			}
    		}
    	} catch (SecurityException se) {
    		System.out.println("DefectTableModel : SecurityException - "+se.getMessage()); //$NON-NLS-1$
    	}
     
    	if (retArray == null) {
    		retArray = EMPTY_CHILDREN;
    	}
    	return retArray;
    }
    C'est ça qui prend du temps, je pense...

    4) Méthode load() appelée juste dans le 1) :
    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
     
    public void load() {
    	DefectNode[] children = node.getChildren();
     
    	sizeMS = getSizeSorter();
    	for (int counter = children.length - 1; counter >= 0; counter--) {
    		if (!children[counter].isLeaf()) {
    			reloadNode = children[counter];
    			loadChildren(children[counter]);
    			reloadNode = null;
    		}
    		if (!isValid) {
    			counter = 0;
    		}
    	}
    	recycleSorter(sizeMS);
    	if (isValid) {
    		MergeSort sorter = getSizeSorter();
    		sorter.sort(node.getChildren());
    		recycleSorter(sorter);
    		node.setChildren(node.getChildren(), true);
    		synchronized (DefectTableModel.this) {
    			reloadCount--;
    			DefectTableModel.this.notifyAll();
    		}
    	} else {
    		synchronized (DefectTableModel.this) {
    			reloadCount--;
    			DefectTableModel.this.notifyAll();
    		}
    	}
    }
    5) Méthode loadChildren() appelée juste au dessus :
    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
     
    protected void loadChildren(DefectNode node) {
    	if (!node.isLeaf()) {
    		final DefectNode[] children = node.createChildren(null);
     
    		for (int counter = children.length - 1; counter >= 0; counter--) {
    			if (!children[counter].isLeaf()) {
    				children[counter].forceTotalSizeValid();
    			}
    			if (!isValid) {
    				counter = 0;
    			}
    		}
    		if (isValid) {
    			final DefectNode dn = node;
     
    			// Reset the children
    			MergeSort sorter = getSizeSorter();
     
    			sorter.sort(children);
    			recycleSorter(sorter);
    			dn.setChildren(children, true);
    			dn.setTotalSizeValid(true);
    			dn.nodeChanged();
    		}
    	} else {
    		node.forceTotalSizeValid();
    	}
    }
    tout ce code a été récupéré dans l'exemple Sun (cf lien en début de topic).

    Et je ne vois pas ce que je peut faire pour que ce reloadChildren() ne bloque pas l'affichage... (à part le sortir de l'EDT, mais apparemment, ce n'est pas ce qu'il faut faire...)

    Une idée pour me débloquer?...

Discussions similaires

  1. Réponses: 6
    Dernier message: 31/12/2011, 07h03
  2. jointure sur plusieurs tables fonctionne pas
    Par jmsch dans le forum Requêtes
    Réponses: 1
    Dernier message: 03/11/2010, 21h55
  3. Réponses: 0
    Dernier message: 02/06/2009, 14h09
  4. Réponses: 4
    Dernier message: 06/08/2007, 16h17

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