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 :

Swing, EDT, et rafraichissement


Sujet :

EDT/SwingWorker Java

  1. #1
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Avril 2006
    Messages
    252
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2006
    Messages : 252
    Par défaut Swing, EDT, et rafraichissement
    Bonjour à tous!

    J'ai réalisé une interface graphique pour un programme de dépouillement qui permet de visualiser un certains nombres de paramètres capteurs (sous forme "graphique", cadran et autre, ou stats via jFreeChart) et une partie vidéo. Je précise que je l'ai réalisé sans connaître l'existence de l'EDT et de SwingWorker, ce qui fait que je me retrouve avec une interface "complète" et pas optimisé (voilà c'est dit). Alors plutôt que de déballer mes problèmes d'un coup, je vais essayer de les exposer au fur et à mesure (merci d'avance à ceux qui auront le courage de suivre cette discussion qui risque de durer..)

    Donc..Problème n°1

    Afin de laisser liberté à l'utilisateur de choisir son agencement, j'ai défini une JFrame qui contient un JPanel qui contient 2 JPanel, fenetreDeGauche et fenetreDeDroite. L'utilisateur peut choisir de "switcher" suivant le schéma suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    graphique et video => par defaut
    graphique et stats
    video et stats
    etc... (il y a impossiblité d'avoir deux mêmes visu en même temps)
    LE problème c'estr que lors du changement par exemple de celui de gauche, il y a un temps de latence pendans lequel le panel de gauche est décalé vers le haut (sur la barre de menu), celui de droite est totu gris, et puis au bout de qqes secondes tout revient dans l'ordre. Il y a d'autres erreurs possibles comme des"traces" du Panel précédent etc...

    Voici le code de changement de Panel:
    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 changementFenetre(String a,int b, int c){
     
    		final String cote=a;
    		final int precedent=b;
    		final int nouveau=c;
    		 	  if(cote.compareTo("droite")==0){
    		      			fenetreDroite.remove(ecrans[precedent]);
    		      			fenetreDroite.add(ecrans[nouveau]);
    		      			fenetreDroite.revalidate();
    		      		}
    		      		else{
    		      			fenetreGauche.remove(ecrans[precedent]);
    		      			fenetreGauche.add(ecrans[nouveau]);
    		      			fenetreGauche.revalidate();
    		      		}
     
     
    		      		repaint();
    			System.out.println("Changement effectué");
    	}
    Sachant que ecrans est tel que:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    this.ecrans[1]=this.tableauDeBord;
    this.ecrans[2]=this.getJPanelVideo();
    this.ecrans[0]=this.getTableauDeStatistiques();
    //ce sont tous des JPanel
    Voilà, j'espère que mon problème est clair...
    Merci

  2. #2
    Membre expérimenté
    Inscrit en
    Janvier 2006
    Messages
    257
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 257
    Par défaut
    Si a partir de ton thread utilisateur tu as besoin de modifier des element graphique (maj de bouton ...) il faut que tu utilise la méthode static SwingUtilities.invokeLater(Runnable).

    Si tu a des opération tres long a mettre en oeuvre, utilise un swingWorker c super plus pratique....

    ex de swingUtilities :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SwingUtilities.invokeLater(new Runnable() {
    public void run() {
    //ici tu met ce que tu veux faire sur les composants 
    textArea.setText(text);
    }
    });
    Pour résumer soit :
    1 - effectue tes opération longue dans un thread a part et fait des appel a InvokeLater pour la recnstruction de la GUI se qui evitera les freeze...
    2 - Creé un swingWorker dans lequel tu surcharge la méthode doInBackground() tu y fait toutes les choses longue dont tu as besoin tu tu appel le swingWorker avec SwingUtilities.invokeLater(new TonSwingWorker()).

    Voila j'espere avoir ete assez clair...

  3. #3
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Avril 2006
    Messages
    252
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2006
    Messages : 252
    Par défaut
    Ben j'avais fait ca:

    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
     
     
    public void changementFenetre(String a,int b, int c){
     
    		final String cote=a;
    		final int precedent=b;
    		final int nouveau=c;
    		new Thread(new Runnable() {
     
    		      public void run() {
    		    	  if(cote.compareTo("droite")==0){
    		      			fenetreDroite.remove(ecrans[precedent]);
    		      			fenetreDroite.add(ecrans[nouveau]);
    		      			fenetreDroite.revalidate();
    		      		}
    		      		else{
    		      			fenetreGauche.remove(ecrans[precedent]);
    		      			fenetreGauche.add(ecrans[nouveau]);
    		      			fenetreGauche.revalidate();
    		      		}
    		       SwingUtilities.invokeLater(new Runnable() {
    		          public void run() {
     
     
    		      		repaint();
    		          }
    		        });
    		      }
    		  }).start();
     
     
     
    		System.out.println("Changement effectué");
    	}
    Mais le problème ne se résolvait pas pour autant...
    Je suis pas sûr d'avoir bien compris comment identifier ce qui doit être exécuté dans l'EDT et ce qui doit se faire en dehors..

  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
    Salut,

    Citation Envoyé par Flophx
    Je suis pas sûr d'avoir bien compris comment identifier ce qui doit être exécuté dans l'EDT et ce qui doit se faire en dehors..
    Tout ce qui touche aux composants doit être exécuté dans l'EDT, et tout le reste devrait être exécuté en dehors...


    Donc dans ton cas la méthode changementFenetre() doit être exécutée dans l'EDT (tu peux vérifié si c'est bien le cas avec SwingUtilities.isEventDispatchThread()).

    a++

  5. #5
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Avril 2006
    Messages
    252
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2006
    Messages : 252
    Par défaut
    Bien, j'ai tout mis dans l'EDT:
    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 changementFenetre(String a,int b, int c){
     
    		final String cote=a;
    		final int precedent=b;
    		final int nouveau=c;
    		new Thread(new Runnable() {
     
    		      public void run() {
    		    	  SwingUtilities.invokeLater(new Runnable() {
    		          public void run() {
     
    		        	  if(cote.compareTo("droite")==0){
    			      			fenetreDroite.remove(ecrans[precedent]);
    			      			fenetreDroite.add(ecrans[nouveau]);
    			      			fenetreDroite.revalidate();
    			      		}
    			      		else{
    			      			fenetreGauche.remove(ecrans[precedent]);
    			      			fenetreGauche.add(ecrans[nouveau]);
    			      			fenetreGauche.revalidate();
    			      		}
    		      		repaint();
    		          }
    		        });
    		      }
    		  }).start();
     
     
     
    		System.out.println("Changement effectué");
    	}
    Mais j'ai toujours les problèmes d'artefacts visuels restants du précédent Panel et le panel nouveau passe un temps au dessus de la barre de menu...
    Ex:
    Images attachées Images attachées  

  6. #6
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Avril 2006
    Messages
    252
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2006
    Messages : 252
    Par défaut
    Ce que je ne comprends pas, c'est pourquoi il s'obstine à se rafraichir sur la barre de menu alors qu'il a les coordonnées exactes de rafraichissement (j'utilise un Layout(null) et setBounds())...

  7. #7
    Membre Expert
    Avatar de natha
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    2 346
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Janvier 2006
    Messages : 2 346
    Par défaut
    Salut,

    Ca fait 5x que quelqu'un poste sur ce forum en disant avoir un problème de position de composants en faisant un setLayout(null) et setBounds(..).

    Il est clair manifestement qu'il ne faut pas utiliser cette méthode mais utiliser un Layout existant. Personnellement je n'ai jamais eu besoin de faire de layout null.

    ++

  8. #8
    Gfx
    Gfx est déconnecté
    Expert confirmé
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Par défaut
    Je ne comprendrai jamais non plus les personnes qui s'obstinent avec le layout null. Mais bon

    Puisqu'on parle de l'EDT ici j'aimerais clarifier quelque chose. *Toutes* les méthodes Swing n'ont pas besoin d'être exécutées dans l'EDT. Prenons l'exemple donné dans cette page :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        //ici tu met ce que tu veux faire sur les composants 
        textArea.setText(text);
      }
    });
    La méthode setText() des composants texte de Swing (ainsi que getText() d'ailleurs) peut-être invoquée en dehors de l'EDT (notez que je suis parfaitement conscient d'avoir utilisé setText() pour illustrer des utilisations de l'EDT ; tout en sachant très bien que ce n'était pas nécessaire ;-). Cela est dû au fait que set/getText manipulent des String, qui sont thread-safe, et font ensuite un repaint(), qui peut être invoqué depuis n'importe quel thread.

    Il y a pas mal d'autres méthodes qui sont sûres. Tous les getXXX() qui renvoient une instance de Color marchent par exemple sûrement en dehors de l'EDT car Color est immuable.

  9. #9
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Avril 2006
    Messages
    252
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2006
    Messages : 252
    Par défaut
    Bien, je me suis débarrassé de tous mes layout(null), ce qui a considérablement amélioré l'ensemble... Mais je me heurte à un problème d'écriture de code, et j'ai besoin d'aide...

    Voici le code en question:

    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
     
    public void actionPerformed(ActionEvent arg0) {
    fc=new JFileChooser();
    						returnVal = fc.showOpenDialog(MenuDemarrerItemOuvrirFichier.this);
    						if (returnVal == JFileChooser.APPROVE_OPTION) {
    							File file = fc.getSelectedFile();
    							String cheminFichier;
    							Loader chargementResultat = new Loader();
    							//This is where a real application would open the file.
    							System.out.println("Fichier ouvert: " + file.getAbsolutePath());
    							cheminFichier = file.getAbsolutePath();
    							chargementResultat=new Loader();
     
    							liste=chargementResultat.load(cheminFichier);
    							chargementFenetre();
    							fenetrePrincipale.initialisationVues(2);
     
     
    							JOptionPane.showMessageDialog(null, "Fichier chargé");
     
    							for (int i=0;i<ecrans.length-1;i++){
    								ecrans[i].start(liste);
    							}
    }
    Mon problème est le suivant, ce qui concerne l'affichage graphique, donc l'EDT, c'est uniquement la création de la boite de dialogue, et ) la fin initialisationVues. Dans tout le reste, j'ai des opérations (longues) qui devraient être exécutées hors EDT.

    Et je n'arrive pas à coder convenablement avec les invokeLater... Quelqu'un peut-il venir à mon secours??

    J'ai tout mis dans un seul "bolc" safe", mais ca "force" les opérations longues dans l'EDT (= idiot) et dans deux blocs consécutifs, mais ca marche pas....

  10. #10
    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
    Tu devrais te tourner vers la classe SwingWorker : http://rom.developpez.com/java-swingworker/

    Ce qui donnerait un pattern du style (pour faire simple) :
    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
    	public void actionPerformed(ActionEvent event) {
     
    		// Modification de l'interface graphique avant le traitement
     
    		new SwingWorker() {
    			protected abstract Object doInBackground() {
    				// Ici le traitement a exécuté en tâche de fond
    			}
     
    			protected void done() {
    				// Ici les modifications de l'interface graphique
    				// à faire à la fin du traitement
    			}
    		}.execute(); // exécute le traitement en arrière plan
     
    	}
    Cette classe a été intégré à Java 6,
    mais elle est disponible ici pour Java 5.0 : https://swingworker.dev.java.net/
    ou ici pour les versions précédentes de Java (mais avec une API un peu différente) : http://java.sun.com/products/jfc/tsc.../threads1.html

    a++

  11. #11
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Citation Envoyé par Gfx
    La méthode setText() des composants texte de Swing (ainsi que getText() d'ailleurs) peut-être invoquée en dehors de l'EDT (notez que je suis parfaitement conscient d'avoir utilisé setText() pour illustrer des utilisations de l'EDT ; tout en sachant très bien que ce n'était pas nécessaire ;-). Cela est dû au fait que set/getText manipulent des String, qui sont thread-safe, et font ensuite un repaint(), qui peut être invoqué depuis n'importe quel thread.
    Malheureusement, cela ne suffit pas à être thread-safe (même si la javadoc le dit, je crois qu'ils se sont plantés, ça ne sera pas la première fois en ce qui concerne la synchro).

    La synchronisation (avec le mot-clé synchronized) permet plusieurs choses :
    - l'exclusion mutuelle
    - la mise en cohérence des caches

    Pour éviter d'avoir à synchroniser, Swing utilise un thread unique (l'EDT), qui remplit également l'exclusion mutuelle, et qui n'a pas besoin de mise en cohérence des caches, le thread étant unique.

    Si tu fais un .setText() (ou un getText()) à partir d'un autre thread, ok tu n'as plus besoin d'exclusion mutuelle grâce à l'immutabilité des String, mais il manque la cohérence des caches, et donc théoriquement (mais avec une probabilité infiniement faible), un .setText() effectué par un thread pourrait ne jamais être vu par l'EDT, et donc la valeur pourrait ne jamais avoir été modifiée...

    Ils ont fait la même erreur dans EventListenerList:
    http://www.developpez.net/forums/sho...d.php?t=267084


    À moins que tu me sortes un lien de sun qui explique qu'ils ont un truc magique pour s'assurer que les caches sont cohérents... (ce que j'aimerais assez)

  12. #12
    Membre éclairé
    Profil pro
    Étudiant
    Inscrit en
    Avril 2006
    Messages
    252
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2006
    Messages : 252
    Par défaut
    Je voudrais juste savoir si avec le swingworker, je peux les "enchainer" dans l'actionperformed, à savoir quelquechose de ce type

    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
     
    public void actionPerformed(ActionEvent event) {
     
    		// Modification de l'interface graphique avant le traitement
     
    		new SwingWorker() {
    			protected abstract Object doInBackground() {
    				// Itraitement1
    			}
     
    			protected void done() {
    				//JFile Chooser
    			}
    		}.execute(); // exécute le traitement en arrière plan
     
    // Modification de l'interface graphique avant le traitement
     
    		new SwingWorker() {
    			protected abstract Object doInBackground() {
    				// traitement 2
    			}
     
    			protected void done() {
    				// => Chargement interface graphique
    			}
    		}.execute(); // exécute le traitement en arrière plan
    	}

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/03/2014, 17h51
  2. Swing, EDT, menu non bloquant
    Par visiwi dans le forum EDT/SwingWorker
    Réponses: 7
    Dernier message: 01/06/2008, 22h36
  3. Swing et l'EDT
    Par zulkifli dans le forum EDT/SwingWorker
    Réponses: 6
    Dernier message: 11/10/2007, 20h14
  4. [SWING] Problème de rafraichissement
    Par david71 dans le forum AWT/Swing
    Réponses: 3
    Dernier message: 24/05/2004, 16h38

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