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

Agents de placement/Fenêtres Java Discussion :

Label dans une fenêtre lancée par un thread qui ne s'affiche pas !


Sujet :

Agents de placement/Fenêtres Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 74
    Points : 40
    Points
    40
    Par défaut Label dans une fenêtre lancée par un thread qui ne s'affiche pas !
    Bonjour (et bonnes fêtes),
    Voici le problème que je rencontre.
    J'essaye de simuler une "progressBar", en prenant un peu le contrepied de la démarche habituelle, consistant si j'ai bien tout compris à placer le traitement qui peut prendre du temps dans un thread et à afficher une barre de progression en fonction. En effet, dans mon cas c'est la barre de progression que j'essaye de mettre dans un nouveau thread ! En effet, le traitement qui prend du temps est bloquant, et le programme ne doit pas passer à l'instruction suivante tant que ce traitement n'est pas terminé. Donc si je fais un nouveau thread rien que pour ce traitement (ou si j'utilise le SwingWorker), ça merdoie ...

    Mais voilà mon problème concrètement : j'ai une interface principale, et un bouton qui lance le traitement en question, qui va lui-même se charger de traiter la progress bar (qui est sous forme de texte : affichage du % d'avancement), en créant une nouvelle fenêtre secondaire dans un nouveau thread.
    Le problème que je rencontre est que l'on ne voit rien dans la fenêtre où sont sensées s'afficher les infos de progression !
    En fait, je me suis aperçu, que si je lançais la fenêtre sans passer par le bouton, ça marchait (on voit la progression), alors que si l'on essaye par l'intermédiaire du bouton (c'est comme ça que ça devrait marcher), eh bin rien...

    Voici le code : ProgressBarPerso qui fait le traitement en appelant la fenêtre, et TestProgressBarPerso qui crée l'ihm principale et propose le bouton pour appeler le traitement. Quand on lance le test, on peut voir la fenêtre qui fait le traitement avec l'affichage, tout est ok (sauf que ce n'est pas comme ça que je veux lancer mon traitement). Mais quand on appuie sur le bouton "Go", on ne voit rien jusqu'à ce que le traitement soit fini...

    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
    83
    84
    85
    86
    87
    88
    89
    90
    91
    package Essai ;
     
    import javax.swing.JFrame ;
    import javax.swing.JLabel ;
    import javax.swing.JPanel ;
     
    class ProgressBarPerso extends JFrame
    {
    	private JLabel label = new JLabel() ;
    	private JPanel pan = new JPanel() ;
     
    	ProgressBarPerso()
    	{
    		this.setTitle("Extraction...") ;
    		this.setLocationRelativeTo(null) ;
    		this.setSize(300, 100) ;
    		pan.add(label) ;
    		this.setContentPane(pan) ;
    		this.setVisible(true) ;
     
    		Progress prog = new Progress() ;
    		Thread thProgres = new Thread(prog) ;
    		thProgres.start() ;
    		prog.setContinuer(true) ;
    		int v = 0 ;
    		while (v <= 100)
    		{
    			try
    			{
    				Thread.sleep(100) ;
    			}
    			catch (InterruptedException e)
    			{
    				// TODO Auto-generated catch block
    				e.printStackTrace() ;
    			}
    			v += 5 ;
    			prog.setPourcent(v) ;
    		}
    		prog.setContinuer(false) ;
    	}
     
    	private class Progress extends JPanel implements Runnable
    	{
    		private String texteAAfficher = "" ;
    		private int pc = 0 ;
    		private boolean continuer = false ;
    		private long tps = 100 ;
    		private boolean afficher = false ;
     
    		@Override
    		public void run()
    		{
    			while (true)
    			{
    				if (continuer)
    				{
    					label.setText(texteAAfficher) ;
    					repaint() ;
    				}
    				try
    				{
    					Thread.sleep(tps) ;
    				}
    				catch (InterruptedException e)
    				{
    					Thread.currentThread().interrupt() ;
    					break ;
    				}
    				synchronized (this)
    				{
    					Thread.yield() ;
    					continuer = this.afficher ;
    				}
    			}
    		}
     
    		public void setPourcent(int v)
    		{
    			pc = v ;
    			texteAAfficher = "Travail effectué : " + Integer.toString(pc) + " %" ;
    			repaint() ;
    		}
     
    		public void setContinuer(boolean c)
    		{
    			this.afficher = c ;
    		}
    	}
     
    }
    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
    package Essai ;
     
    import java.awt.BorderLayout;
    import java.awt.Button;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
     
    import javax.swing.JFrame ;
    import javax.swing.JPanel;
     
    public class TestProgressBarPerso extends JFrame
    {
     
    	private JPanel pan = new JPanel () ;
    	private Button bouton = new Button("Go") ;
    	private ProgressBarPerso pbp ;
    	private ProgressBarPerso prog ;
     
    	public TestProgressBarPerso()
    	{
     
    		this.setTitle("Essai pour ProgressBar") ;
    		this.setSize(300, 300) ;
    		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
    		this.setLocationRelativeTo(null) ;
    		this.add(bouton, BorderLayout.NORTH) ;
    		this.setVisible(true) ;
     
    		bouton.addActionListener(new ActionListener()
    		{
    			@Override
    			public void actionPerformed(ActionEvent e)
    			{
    				pbp = new ProgressBarPerso() ; // Fenêtres suivantes : ça ne marche pas !
    			}
    		}) ;
     
    		prog = new ProgressBarPerso () ; // Première fenêtre : ça marche
    	}
     
    	public static void main(String[] args)
    	{
    		TestProgressBarPerso play = new TestProgressBarPerso() ;	
    	}
     
    }

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    utilisez la classe progressMonitor, elle est déjà concue pour ça. Vous lui donnez son min et son max, vous lui indiquez la progression au fur et à mesure, et si votre processus dure plus qu'un temps limite, elle apparait toute seule.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 74
    Points : 40
    Points
    40
    Par défaut
    Oui, effectivement, je connais (enfin... je sais qu'il existe) une classe pour traiter les fichiers avec des "progressBar", mais ça n'est pas ma question... Ce qui m'intéresse, c'est comprendre ce qui se passe, et surtout ce qui ne se passe pas dans mon cas ! Que ça puisse marcher autrement, j'imagine que c'est le cas (encore qu'avec l'exemple traité dans la doc d'oracle, ils utilisent des SwingWorker à tour de bras et des threads, ce qui ne m'intéresse absolument pas -> adaptation non aisée pour un débutant ).

    Je regarde du côté de l'article sur les threads et Swing trouvé dans une autre discussion, ça ne peut pas me faire de mal, mais je ne sais pas si la réponse à mon problème est à chercher de ce côté...

    Donc je reste preneur d'une explication sur ce qui ne va pas, ça me fera progresser.

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

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Le threads ou swingworkers sont obligatoires si tu veux avoir un traitement long avec une interface qui ne soit pas figée durant le traitement.

    La raison se trouve dans le tuto suivant: http://gfx.developpez.com/tutoriel/j...ing-threading/
    Hey, this is mine. That's mine. All this is mine. I'm claiming all this as mine. Except that bit. I don't want that bit. But all the rest of this is mine. Hey, this has been a really good day. I've eaten five times, I've slept six times, and I've made a lot of things mine. Tomorrow, I'm gonna see if I can't have sex with something.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 74
    Points : 40
    Points
    40
    Par défaut
    Citation Envoyé par sinok Voir le message
    Le threads ou swingworkers sont obligatoires si tu veux avoir un traitement long avec une interface qui ne soit pas figée durant le traitement.

    La raison se trouve dans le tuto suivant: http://gfx.developpez.com/tutoriel/j...ing-threading/
    C'est l'article que j'évoquais, je suis en train de le lire.
    Mais mon problème demeure et je ne pense pas que ce soit lié aux performances swing/thread parce que :
    1) j'utilise un thread (pour l'affichage du graphique)
    2) ça marche la première fois (quand j'appelle le thread dès le début de la classe), mais pas ensuite, quand je fais un appel depuis un bouton.
    Je crois que c'est plutôt au niveau de l'imbrication des deux fenêtres.

    Du reste, j'ai essayé avec un monitor comme suggéré ci-dessus : j'ai le même problème : la fenêtre de progression apparaît, mais elle ne contient pas l'affichage attendu (c'est comme si elle était vide, on peut voir ce qu'il y a derrière lors de son affichage !).
    D'où mon problème (probablement une erreur ou une maladresse de codage), qui demeure entier. Peut-être pas grand chose, un paint ou un repaint pas ou mal placé, ou une réinitialisation qui n'est pas faite...

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

    Informations forums :
    Inscription : Août 2004
    Messages : 8 765
    Points : 12 977
    Points
    12 977
    Par défaut
    Il ne faut en aucun cas accéder au ressources de l'EDT (à savoir les composants Swing & cie) dans un thread externe. Tout méthode de composant Swing doit être appelée dans l'EDT sauf mention contraire dans la javadoc, soit en utilisant un SwingUtilities.invokeLater si on est dans un thread, soit la méthodes done et un PropertyChangeListener pour le SwingWorker.
    Hey, this is mine. That's mine. All this is mine. I'm claiming all this as mine. Except that bit. I don't want that bit. But all the rest of this is mine. Hey, this has been a really good day. I've eaten five times, I've slept six times, and I've made a lot of things mine. Tomorrow, I'm gonna see if I can't have sex with something.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 74
    Points : 40
    Points
    40
    Par défaut
    D'accord, je comprends qu'il y a peut-être un défaut à ce niveau. J'ai essayé de lancer mon thread graphique avec le "invokeLater", mais ça ne marche pas mieux (c'est même moins bien : ça boucle, et il faut que je ferme l'application avec le carré rouge d'Eclipse !).
    En fait, ça ne me surprend qu'à moitié car en lisant la doc, il est expliqué à propos d'invokeLater :

    This method should be used when an application thread needs to update the GUI.
    Dans mon cas, c'est l'inverse que je veux faire : rafraîchir un thread définissant un composant graphique SWING à partir du programme principal qui est mon GUI.

    Pourquoi je veux faire ça ? Je rappelle ce que j'ai en tête, peut-être que c'est là qu'il y a un problème :
    j'ai une tâche assez longue (dézipper des fichiers), que l'utilisateur lance en cliquant sur un bouton. Dès que ce traitement est terminé (et surtout pas avant !), le programme utilise l'un de ces fichiers (on ne sait pas lequel : le premier ? le dernier ?). Donc le traitement de dézippage doit être "bloquant" par rapport à l'instruction suivante. Je veux indiquer à l'utilisateur où en est le processus de dézippage dans une petite fenêtre que je fais moi-même, sans utiliser de choses toutes faites (disons c'est dans le cahier des charges ).
    Comment résoudre ce problème ?
    Je n'attends pas du code tout fait, mais plutôt des idées au niveau de la conception (nouveau thread, pas nouveau thread, éventuellement astuce, etc.), c'est ainsi que je progresserai .

  8. #8
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par totojava Voir le message
    j'ai une tâche assez longue (dézipper des fichiers), que l'utilisateur lance en cliquant sur un bouton. Dès que ce traitement est terminé (et surtout pas avant !), le programme utilise l'un de ces fichiers (on ne sait pas lequel : le premier ? le dernier ?). Donc le traitement de dézippage doit être "bloquant" par rapport à l'instruction suivante. Je veux indiquer à l'utilisateur où en est le processus de dézippage dans une petite fenêtre que je fais moi-même, sans utiliser de choses toutes faites (disons c'est dans le cahier des charges ).
    Lorsqu'on clique sur le bouton, afficher une popup avec la barre (ca bloque l'application) et lancer un thread de dezippage. Fin du travail du bouton

    Thread de dezippage: faire le travail et, réguilèrement, mettre à jour la popup via invoke later. Fin du dezippage, cacher la popup, via invoke later.

    Etonnament, tout un travail que fait déjà le swing worker :/

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 74
    Points : 40
    Points
    40
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Lorsqu'on clique sur le bouton, afficher une popup avec la barre (ca bloque l'application) et lancer un thread de dezippage. Fin du travail du bouton

    Thread de dezippage: faire le travail et, réguilèrement, mettre à jour la popup via invoke later. Fin du dezippage, cacher la popup, via invoke later.

    Etonnament, tout un travail que fait déjà le swing worker :/
    C'est là que ça n'allait pas dans ma conception : je voulais absolument lancer le traitement et faire appeler la fenêtre graphique à partir de celui-ci ! C'est effectivement l'inverse qu'il faut faire en commençant par lancer la fenêtre ("popup") qui appelle le thread... Il fallait que je pense à l'envers, mais je n'arrivais pas à sortir de mon schéma de départ .
    Et là je vois clairement le lien avec le SwingWorker...

    Bon, je vais essayer de mettre ça en place quand j'aurai un peu de temps, et je reviendrai avec une solution et/ou des questions.

    Merci .

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2010
    Messages
    74
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2010
    Messages : 74
    Points : 40
    Points
    40
    Par défaut
    Bonjour,

    Alors voilà une solution à ma question. Ca n'utilise pas SwingWorker (java 6, et j'ai été obligé de travailler en 5), mais ça répond bien à la question posée.
    Sur les conseils donnés, j'ai renversé la façon de procéder, comme expliqué dans le message précédent.
    Merci.

    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
     
    package Essai;
     
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
     
    import javax.swing.JButton;
    import javax.swing.JFrame;
     
    public class TestProgressBar extends JFrame {
     
    	public TestProgressBar() {
    		this.setTitle("Fenêtre principale") ;
    		this.setSize(600, 400) ;
    		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) ;
    		this.setLocationRelativeTo(null) ;
    		final JButton bouton = new JButton("START") ;
    		bouton.addActionListener(new ActionListener() {
     
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				bouton.setEnabled(false) ;
    				new ProgressBarPerso() ;
    			}
     
    		}) ;
    		this.add(bouton, BorderLayout.NORTH) ;
    		this.setVisible(true) ;	
    	}
     
    	public static void main(String[] args)
    	{
    		System.out.println("DEBUT") ;
    		new TestProgressBar() ;	
    	}
    }
    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
     
    package Essai ;
     
    import javax.swing.JFrame ;
    import javax.swing.JLabel ;
    import javax.swing.JPanel ;
    import javax.swing.SwingUtilities ;
     
    class ProgressBarPerso extends JFrame {
    	private JLabel	label				= new JLabel() ;
    	private JPanel	pan				= new JPanel() ;
    	private String	texteAAfficher	= "" ;
     
     
    	ProgressBarPerso() {
    		this.setTitle("Extraction...") ;
    		this.setLocationRelativeTo(null) ;
    		this.setSize(300, 150) ;
    		pan.add(label) ;
    		this.setContentPane(pan) ;
    		this.setVisible(true) ;
    		Progress prog = new Progress() ;
    		Thread thProgres = new Thread(prog) ;
    		thProgres.start() ;
    	}
     
     
    	public void setPourcent(int v) {
    		texteAAfficher = "Travail effectué : " + Integer.toString(v) + " %" ;
    		label.setText(texteAAfficher) ;
    		repaint() ;
    	}
     
     
    	private class Progress extends JFrame implements Runnable {
    		@Override
    		public void run() {
    			int v = 0 ;
    			while (v <= 95) {
    				try {
    					Thread.sleep(300) ;
    				}
    				catch (InterruptedException e) {
    					e.printStackTrace() ;
    				}
    				v += 5 ;
    				setPourcent(v) ;
    			}
    		}
    	}
    }

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

Discussions similaires

  1. Ecran de démarrage multi thread qui ne s'affiche pas sur un pc
    Par jacko842 dans le forum Windows Forms
    Réponses: 0
    Dernier message: 16/01/2013, 12h14
  2. Réponses: 12
    Dernier message: 11/09/2012, 19h48
  3. Réponses: 3
    Dernier message: 31/05/2011, 18h25
  4. [vs 2005]réduire une fenêtre lancée par Process
    Par tatikambwa dans le forum C#
    Réponses: 1
    Dernier message: 28/10/2008, 14h02
  5. Réponses: 2
    Dernier message: 06/02/2007, 17h18

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