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

EDT/SwingWorker Java Discussion :

Erreurs Swing lors de la MAJ rapide (en rafale) d'une JTable


Sujet :

EDT/SwingWorker Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 99
    Par défaut Erreurs Swing lors de la MAJ rapide (en rafale) d'une JTable
    Salut,
    j'utilise une JTable pour afficher le contenu d'un fichier de log (3 colonnes, type, date et msg). Certains processus ajoutent des lignes à ce fichier pendant leur exécution (log) et envoient un event à ma table via un écouteur à chaque ligne ajoutée. L'écouteur relit le fichier et fait un setModel avec une classe fille d'AbstractTableModel. Lorsque les evt ne sont pas trop rapides, pas de pb, par contre lorsque les evt s'enchainent rapidement (plusieurs par seconde) j'ai l'erreur :

    Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException: Vector Enumeration
    at java.util.Vector$1.nextElement(Unknown Source)
    at javax.swing.plaf.basic.BasicTableHeaderUI.getPreferredSize(Unknown Source)
    at javax.swing.JComponent.getPreferredSize(Unknown Source)
    at javax.swing.ViewportLayout.preferredLayoutSize(Unknown Source)
    at java.awt.Container.preferredSize(Unknown Source)
    at java.awt.Container.getPreferredSize(Unknown Source)
    at javax.swing.JComponent.getPreferredSize(Unknown Source)
    at javax.swing.ScrollPaneLayout.layoutContainer(Unknown Source)
    at java.awt.Container.layout(Unknown Source)
    at java.awt.Container.doLayout(Unknown Source)
    at java.awt.Container.validateTree(Unknown Source)
    at java.awt.Container.validate(Unknown Source)
    at javax.swing.RepaintManager.validateInvalidComponents(Unknown Source)
    at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)


    et aussi

    Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 0 >= 0
    at java.util.Vector.elementAt(Unknown Source)
    at javax.swing.table.DefaultTableColumnModel.getColumn(Unknown Source)
    at javax.swing.plaf.basic.BasicTableHeaderUI.getHeaderRenderer(Unknown Source)
    at javax.swing.plaf.basic.BasicTableHeaderUI.getHeaderHeight(Unknown Source)
    at javax.swing.plaf.basic.BasicTableHeaderUI.createHeaderSize(Unknown Source)
    at javax.swing.plaf.basic.BasicTableHeaderUI.getPreferredSize(Unknown Source)
    at javax.swing.JComponent.getPreferredSize(Unknown Source)
    at javax.swing.ViewportLayout.preferredLayoutSize(Unknown Source)
    at java.awt.Container.preferredSize(Unknown Source)
    at java.awt.Container.getPreferredSize(Unknown Source)
    at javax.swing.JComponent.getPreferredSize(Unknown Source)
    at javax.swing.ScrollPaneLayout.layoutContainer(Unknown Source)
    at java.awt.Container.layout(Unknown Source)
    at java.awt.Container.doLayout(Unknown Source)
    at java.awt.Container.validateTree(Unknown Source)
    at java.awt.Container.validate(Unknown Source)
    at javax.swing.RepaintManager.validateInvalidComponents(Unknown Source)
    at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

    Je soupçonne mes mises à jour de modèle très rapides de changer le modèle alors que Swing n'a pas fini d'afficher le modèle affecté précédemment (genre au début il a n lignes et pendant que swing affiche ces n lignes, tout d'un coup le modèle change et en comporte moins par exemple)

    Comment faire pour régler ce pb ?

    merci

  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 soupçonne plus précisément une modification du modèle en dehors de l'EDT...

    On pourrait voir le code de l'écouteur ?

    a++

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 99
    Par défaut
    Voila voila

    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
     
     
    private void addFishConfigNucleusListener(final FishConfig fishConfig)
    {
     
    fishConfig.addNucleusListener(new NucleusListener()
    {
    	public void nucleusChanged(NucleusEvent nucleusEvent)
    		{
    		if (fishConfig.getSelectedNode() != null)
    			{
    			if (fishConfig.getSelectedNodeParentNucleus().equals(nucleusEvent.getNucleus()))
    				{
    				table.setModel(new CustomTableModel(getSelectedNodeData(fishConfig.getSelectedNode(), fishConfig)));
    				}
    			}
    		}
    });
     
    }
    Je me suis toujours demandé si les évènements étaient traités dans le même thread que le reste de l'interface graphique ...

  4. #4
    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 cdtkoenig Voir le message
    Je me suis toujours demandé si les évènements étaient traités dans le même thread que le reste de l'interface graphique ...
    Les évènements sont traités dans le thread qui les émets.
    Pour les évènements graphique c'est bien géré par l'EDT, mais dans ton cas c'est difficile à dire car ce n'est pas un listener standard...


    Il faudrait voir le code qui emet cet evènement, ou plus simple vérifier le thread dans le listener :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    System.out.println( Thread.currentThread() + " isEDT=" + SwingUtilities.isEventDispatchThread() );
    a++

    PS : Sinon, pourquoi relire tout le fichier ? Ne serait-il pas plus simple d'attendre les modifications sur le fichier plutôt que de tout relire ?

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 99
    Par défaut
    Les evt sont envoyés depuis un autre thread (Thread[Processing 1,6,main] isEDT=false) qui fait des calculs. L'idée est de ne pas lancer de traitement lourd dans l'edt pour ne pas la bloquer, j'utilise donc des evt envoyés depuis les process de calcul pour rafraichir l'interface. Mais cela semble poser problème quand trop d'evt arrivent ...

    As-tu une idée pour résoudre de pb ?

    Je pensais optimiser la lecture du fichier plus tard, mais puisque tu as réagi (je m'en doutais ) Je pensais stocker le dernier no de ligne lu pour ne relire que la fin mais cela implique de tout parcourir jusqu'à ce no

    Tu ferais comment toi ?


    Merci

  6. #6
    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
    Faire les modification en dehors de l'EDT est une façon incorrecte de fair, cf http://gfx.developpez.com/tutoriel/j...ing-threading/

    Ton setModel devrait être appelé dans un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SwingUtilities.invokeLater(Runnable r);
    afin de t'assurer de la bonne synchronisation des évènements.

  7. #7
    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 cdtkoenig Voir le message
    L'idée est de ne pas lancer de traitement lourd dans l'edt pour ne pas la bloquer, j'utilise donc des evt envoyés depuis les process de calcul pour rafraichir l'interface. Mais cela semble poser problème quand trop d'evt arrivent ...
    Le fait de lancer les traitements "lourds" dans un autre thread est très bien
    C'est d'ailleurs ce qui est recommandé de faire !

    Toutefois il faut dans le même temps respecter les consignes de l'EDT, c'est à dire de ne pas manipuler les éléments de l'interface graphique en dehors de l'EDT.

    Citation Envoyé par cdtkoenig Voir le message
    As-tu une idée pour résoudre de pb ?
    En clair, il faut faire tes traitements hors-EDT, et une fois que tu as obtenu tes données il faut les "passer" à l'EDT pour qu'il les insères (qu'il modifie le modèle dans ton cas).

    Pour cela tu peux utiliser SwingUtilities.invokeLater() ou la classe SwingWorker qui facilite le tout.


    Citation Envoyé par cdtkoenig Voir le message
    Je pensais optimiser la lecture du fichier plus tard, mais puisque tu as réagi (je m'en doutais ) Je pensais stocker le dernier no de ligne lu pour ne relire que la fin mais cela implique de tout parcourir jusqu'à ce no

    Tu ferais comment toi ?
    Ca dépend beaucoup de la manière dont tu dois recevoir les données.
    D'après ton descriptif tu reçois cela par un ajout dans un fichier. S'il s'agit bien d'un ajout à la fin tu peux te contenter d'une seule et unique lecture sans refermer le flux : lorsque tu atteins la fin du fichier tu fais une pause pour retenter une lecture "plus tard" tu pourras ainsi recevoir les données qui ont été ajoutés...

    Exemple vite-fait avec une JTable affichant un fichier texte :
    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
    76
    77
    78
    79
    80
    81
    82
    	/*
    	 * Le modèle de données de la table
    	 * (on pourrait utiliser son propre modèle en cas de besoin spécifique)
    	 */
    	final DefaultTableModel model = new DefaultTableModel(0, 2);
     
    	/*
    	 * Le SwingWorker utilisé pour récupéré les données en tâches de fond.
    	 * Paramètrage :
    	 *		<Void> : type de retour de doInBackground() (inutilisé dans ce cas précis)
    	 *		<Object[]> : le types des données à faire transité vers l'EDT
    	 *					(une ligne du modèle dans cet exemple)
    	 *					(on utilisera un type plus spécifique de préférences)
    	 */
    	SwingWorker<Void, Object[]> worker = new SwingWorker<Void, Object[]>() {
     
    		/*
    		 * La méthode doInBackground() est exécutée dans un thread spécifique,
    		 * et permet donc de faire des traitements "lourds" ou bloquant sans
    		 * impacter l'EDT et l'interface graphique...
    		 */
    		@Override
    		protected Void doInBackground() throws Exception {
    			BufferedReader reader = new BufferedReader(new FileReader("in.txt"));
    			try {
    				int index = 0;
    				while (true) {
     
    					// On lit le fichier jusqu'à la fin :
    					String line;
    					while ( (line=reader.readLine()) != null ) {
    						if ( ! line.trim().isEmpty() ) {
    							// Pour chaque ligne lu on décrypte les données :
    							Object[] data = new Object[]{index, line};
    							index ++;
    							// Puis on les "publie"
    							// Cela a pour effet de "passer" les données à l'EDT
    							// via la méthode process() ci-dessous.
    							publish(data);
    						}
    					}
     
    					// Une fois arrivé à la fin du fichier on ne le ferme pas.
    					// A la place on fait une pause pour retenter de le lire
    					// au cas où des données serait ajouté à la fin du fichier.
    					Thread.sleep(500);
     
    				}
     
    			} finally {
    				reader.close();
    			}
    		}
     
    		/*
    		 * La méthode process() est appelée dans l'EDT. On peut donc y faire
    		 * des modifications sur l'interface graphique.
    		 * 
    		 *  Cette méthode reçoit en paramètre les éléments passés à la méthode publish().
    		 *  En clair un appel à publish() dans doInBackground()
    		 *  génèrera un appel à process() dans l'EDT.
    		 */
    		@Override
    		protected void process(List<Object[]> chunks) {
    			// Note : il faut parcourir tous les éléments,
    			// car plusieurs appels à publish() peuvent générer
    			// un seul appel à process() avec plusieurs paramètres...
    			for(Object[] row : chunks) {
    				model.addRow(row);
    			}
    		}
    	};
     
    	// On démarre le worker :
    	worker.execute();
     
    	// Et on affiche la JTable dans une dialogbox :
    	JTable table = new JTable(model);
    	JScrollPane scroll = new JScrollPane(table);
    	scroll.setPreferredSize(new Dimension(200, 400));
     
    	JOptionPane.showMessageDialog(null, scroll);
    a++

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 99
    Par défaut
    Merci pour vos réponse, je vais regarder de plus près cette classe SwingWorker.

    Plus ca va, moins je peux me passer de developpez.com ... tellement c'est bon !

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    99
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2006
    Messages : 99
    Par défaut
    Vu que mes process en tache de fond sont déja codés ailleurs, j'ai opté pour SwingUtilities.invokeLater() qui règle mon pb pile poil. Je Garde sous le coude SwingWorker car j'ai dans l'idée de gèrer le nombre de thread concurent maxi dans mon appli via les executors le tout avec un joli petit panel pour suivre la file d'attente des thread et il me semble que tout ca sent bon le SwingWorker ...

    Dernière question pour la route, je voudrais faire afficher automatiquement la dernière ligne (le dernier evt) par ma JTable lors du refresh du model ... mais je vais poser cette question dans le forum adhoc ( )

    Encore merci à tous !

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

Discussions similaires

  1. [AC-2007] Erreur connexion lors MAJ
    Par lakhdar16 dans le forum VBA Access
    Réponses: 8
    Dernier message: 12/04/2012, 15h44
  2. Réponses: 2
    Dernier message: 27/03/2009, 12h30
  3. [ACCESS] [JET] [ADO] Erreur 3000 lors d'un update
    Par Benjamin GAGNEUX dans le forum Bases de données
    Réponses: 5
    Dernier message: 26/08/2004, 22h16
  4. Question facile, erreur bizzare lors d'un Left, Top
    Par SpiderAlpha dans le forum C++Builder
    Réponses: 4
    Dernier message: 05/05/2004, 13h56
  5. Erreur windows lors du malloc
    Par Elessar dans le forum C
    Réponses: 5
    Dernier message: 16/12/2003, 09h53

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