Badr Benmammar bbm@badr-benmammar.com Formation Développeur Java Thread et Swing Badr Benmammar bbm@badr-benmammar.com.

Slides:



Advertisements
Présentations similaires
Réaliser en Java un programme client d’une Base de Données
Advertisements

Conception d’IHM en Java
1 Swing par la pratique contrat Creative Commons Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique.
DOM Document Object Model. Généralités Standard du W3C Parseur XML – Génération dun arbre dobjet – Construction totale de larbre DOM est spécifié en IDL.
SAX Simple API for XML. Généralités API non standard développé par les membres du forum XML-DEV Parseur XML – Orienté événement – Parsing dynamique SAX.
Les Interfaces Graphiques
Gestion des événements (suite)
Programmation événementielle
NSY102 1 NSY102 Conception de logiciels Intranet Concurrence Notes de cours Cnam Paris jean-michel Douin, douin au cnam point fr 25 Février 2013.
TP 7.1 synchronized et join Écrire un programme Java qui crée 1000 threads et maintient un compteur nb du nombre de threads créés jusque-là. Le thread.
Arbres Un premier exemple Contenu Rendu Ecouteurs Parcours
Composants de Swing JavaBeans Actions Boutons Icônes Bordures Curseurs
Composants graphiques de Java
Page 1 Les applets Jacques Lonchamp. Page 2 Présentation Une applet est téléchargée à partir dune machine distante qui fournit le code. Ce chargement.
(Classes prédéfinies – API Java)
Introduction à Java - les « Threads » -
Voisin-Polian : Introduction à Java 1 Introduction à Java - AWT - Frédéric VOISIN – Nicole POLIAN FIIFO - « Remise à Niveau »
Plan du cours 5:Threads introduction Définition Création des Threads
Les Interfaces graphiques Les Swing. Les interfaces graphiques: Introduction Une application est une boîte noire. Prend des entrées et produit des sorties.
Les composants Graphiques Atomiques
Faisons une interface réactive.
Architecture Logicielle pour les IHM
CURSUS DE FORMATION AUX NOUVELLES TECHNOLOGIES DE DEVELOPPEMENT UV Threads Module Java Expert.
Swing et les Interfaces Graphiques
Les entrées /sorties en Java François Bonneville
Connexion base de données
Chapitre IV Object, interfaces, classes imbriquées.
BlueJ_XI 1 Java, les objets : tout de suite ! Gestion des erreurs : les exceptions Notes de cours associées au chapitre 11 tutorial BlueJ
Introduction à la programmation (420-PK2-SL) cours 12 Gestion des applications Technologie de linformation (LEA.BW)
POO-L3 H. Fauconnier1 Chapitre IV 1. classe Object, clonage 2. interfaces 3. classes internes et imbriquées.
Faculté I&C, Claude Petitpierre, André Maurer 1 Java.
1 1 Université Evry Val d'Essonne Y. Laborde Une calculatrice (sans MVC) fonctionnant sur la base d'un modèle en Java.
Écouteurs de click d'une fenêtre
Cours du 19 octobre. POO-L3 H. Fauconnier2 E) Constructeurs et héritage Le constructeurs ne sont pas des méthodes comme les autres: le redéfinition na.
Badr Benmammar Programmation concurrente et temps réel en Java Badr Benmammar
Exceptions (fin) Généricité
Master 1 SIGLIS java Lecteur Stéphane Tallard Chapitre 4 – Structures de contrôle.
Interface graphiques.
NSY102 1 Concurrence compléments Notes de cours Cnam Paris jean-michel Douin, douin au cnam point fr 19 Mars 2007.
Graphical User Interface (GUI)
Composite et Décorateur 1 Composite & décorateur Notes de cours java : les patterns Composite et Décorateur Cnam Paris jean-michel Douin Version du 1er.
Graphical User Interface
JUnit Présentation complète de JUnit et « guide d’utilisation » en 13 transparents.
Programmation concurrente
Design Pattern Memento. Principe : Enregistrer les changements d'états d'un objet Objectif : Pouvoir restituer les états précédents d'un objet.
Faculté I&C, Claude Petitpierre, André Maurer 1 Concepts dhéritage Héritage dimplémentation hasA Héritage de spécialisation isA.
Multi-Thread Jian-Yun Nie
1 Les paquetages («packages»). 2 L'objectif avec les paquetages («packages») est de rendre accessibles aux utilisateurs des classes définies par d'autres.
Exceptions IFT1025: Programmation 2 Jian-Yun Nie.
LIFI-Java 2004 Séance du Jeudi 9 sept. Cours 1. La notion de langage Décrire une tâche à effectuer –programme Écrire à un haut niveau –facile pour lutilisateur.
Formation Développeur Java Applet et interfaces graphiques avec AWT
Badr Benmammar Programmation concurrente et temps réel en Java Badr Benmammar
Java Swing.
Cours 11 Threads. Chapitre X threads threadPOO-L3 H. Fauconnier3 Threads threads: plusieurs activités qui coexistent et partagent des données exemples:
jean-michel Douin, douin au cnam point fr
COURS DE PROGRAMMATION ORIENTEE OBJET :
CSI1502 Principes fondamentaux en conception des logiciels Chapter 8: Gestion des exceptions.
Android UIThread, Thread, Handler et AsyncTask
Fabienne Boyer Laboratoire LIG (INRIA-UJF-INPG) Projet SARDES, INRIA Rhône-Alpes Usage.
Java : Graphique Swing juin 2006 Brigitte Groléas.
Cours 7 Classes locales Clonage Divers: tableaux.
Cours 91 9 Interfaces graphiques avec awt. Cours 92 Plan Introduction : deux bibliothèques graphiques 1.Comment se dessine une fenêtre ?  Un exemple.
Interfaces graphiques. Composants d'interface utilisateur graphique (GUI) 1 Bibliothèques Awt et Swing Procédures communes pour l'utilisation de ces clases.
14 La gestion d’événements
© Sofia ZAIDENBERG CNRS Mai Interface utilisateur graphique en Java Construire une interface graphique en Java (suite) adaptateurs d’événements.
Cours du 5 novembre.
Héritage H. Batatia. plan Notion (que signifie l’héritage) Ecriture en java Héritage multiple (interdit) Instanciation (partie propre et partie héritée)
 1) Il faut connaître le modèle et son fonctionnement  2) Définir le contrôle que l’on veut faire ouvrir, fermer, afficher, etc.) sur le modèle  3)
Java Swing. Principes de base  Des composants graphiques (exemple: JFrame, JButton …)  Hiérarchie de classes  Des événements et les actions à effectuer.
Présentation SWING Siwar hadj hassen Omar ben yahya.
Transcription de la présentation:

Badr Benmammar bbm@badr-benmammar.com Formation Développeur Java Thread et Swing Badr Benmammar bbm@badr-benmammar.com

Plan Tâche longue dans un une interface utilisateur graphique (GUI ) Deadlock d’initialisation de GUI Pattern de création d’un GUI Tâche périodique dans un GUI Règle d’unicité du thread GUI Class SwingWorker : tâche longue proprement Tâche longue avec interruption possible Interaction avec l’event-dispatcher

Tâche longue dans un GUI Problème : exécuter une tâche relativement longue dans le cadre d’une (GUI) interface graphique pour l’utilisateur. La tâche dure quelques secondes voire des minutes. L’interface doit pouvoir encore réagir aux actions de l’utilisateur. La longue tâche à exécuter est simulée par des "sleep" dans sa méthode execute(). Elle doit indiquer son avancement dans une barre de progression, mais aussi dans la console.

Tâche longue dans un GUI import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTacheLongue1 extends JFrame { JProgressBar barreProgression; public GUIetTacheLongue1() { super("GUIetTacheLongue1"); Container contentPane = getContentPane(); barreProgression = new JProgressBar(); JButton bouton= new JButton("Demarrer la tache longue"); contentPane.add(bouton,BorderLayout.NORTH); contentPane.add(barreProgression,BorderLayout.SOUTH); bouton.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { LongueTache1 tache = new LongueTache1(); tache.execute(barreProgression); } ); pack(); setVisible(true); } public static void main(String[] args) { new GUIetTacheLongue1(); } La tâche longue class LongueTache1 { public void execute (JProgressBar barreProgression) { barreProgression.setMinimum(0); barreProgression.setMaximum(99); barreProgression.setValue(0); for (int i = 0; i < 100; i++ ) { barreProgression.setValue(i); System.out.print("."); try {Thread.sleep(100);} catch (InterruptedException e) {} } System.out.println("") ; Classe interne anonyme pour installer un écouteur correspond au composant bouton

Tâche longue dans un GUI Exécution: ................................. ............................................... $ Remarque : Arrêtez avec <ctrl-C> car la fermeture de la fenêtre et l’arrêt de l’appli ne sont pas prévus pour alléger le code. La "longue tâche", visiblement, fonctionne car elle se trace dans la console. Mais la barre de progression Swing n’est mise à jour qu’à la fin !

Multitâche avec un thread import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTacheLongue2 extends JFrame { JProgressBar barreProgression; public GUIetTacheLongue2() { super("GUIetTacheLongue2"); Container contentPane = getContentPane(); barreProgression = new JProgressBar(); JButton bouton= new JButton("Demarrer la tache longue"); contentPane.add(bouton,BorderLayout.NORTH); contentPane.add(barreProgression,BorderLayout.SOUTH); bouton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Thread t = new Thread() { public void run() { LongueTache2 tache = new LongueTache2(); tache.execute(barreProgression); } }; t.start(); } } ); pack(); setVisible(true);} //fin constructeur public static void main(String[] args) { new GUIetTacheLongue2(); } } // fin de la classe GUIetTacheLongue2 class LongueTache2 { public void execute (JProgressBar barreProgression) { barreProgression.setMinimum(0); barreProgression.setMaximum(99); barreProgression.setValue(0); for(int i = 0; i < 100; i++ ) { barreProgression.setValue(i); System.out.print("."); try {Thread.sleep(100); } catch (InterruptedException e) {} } System.out.println("") ; Une nouvelle classe interne anonyme qui est imbriquée dans la précédente classe interne anonyme afin d’implémenter le thread.

Multitâche avec un thread Pour que la longue tâche et le Gui soient exécutés "en même temps", on lance un thread de plus pour la longue tâche. Exécution : ................................. ............................................... $ Le thread "longue tâche", visiblement, fonctionne car il se trace dans la console et la barre de progression Swing est mise à jour progressivement.

Utilitaire pour tracer les threads import java.awt.*; import java.awt.event.*; import javax.swing.*; class ThreadSwing { public static void main(String args[]) { System.out.println("main -----> thread name = " + Thread.currentThread().getName()); JFrame frame = new JFrame("ThreadSwing"); JButton bouton = new JButton("Afficher"); frame.getContentPane().add(bouton); bouton.addActionListener(new ActionListener() { public void actionPerformed (ActionEvent e) { System.out.println ("actionPerformed -----> thread name = " +Thread.currentThread().getName()); } }); frame.pack(); frame.setVisible(true); Exécution : main -----> thread name = main actionPerformed -----> thread name = AWT-EventQueue-0

Utilitaire pour tracer les threads Ce code s’exécute sur 2 threads : main pour pack, setVisible (réaliser les composants). AWT-EventQueue-0 pour l’action (les événements). Swing (et AWT) dispose d’un thread spécifique pour traiter les événements : l’event dispatcher : AWT-EventQueue-0 qui exécute les "handlers"/méthodes associées aux événements. Une file permet de mettre en attente ordonnée les événements qui arrivent.

Deadlock d’initialisation de GUI import …. public class SwingThreadDeadlock extends JPanel implement ComponentListener{ private static JFrame frame; private JTextArea trace; public SwingThreadDeadlock() { …. } void componentHidden(ComponentEvent e) {} // invoquer quand le composant devient invisible Void componentMoved(ComponentEvent e) {} // invoquer quand le composant change de position Void componentResized(ComponentEvent e) {} // invoquer quand le composant change de taille void componentShown(ComponentEvent e) {} // invoquer quand le composant devient visible private static void createAndShowGUI() { … frame.pack(); frame.setVisible(true); public static void main(String[] args) { createAndShowGUI(); C’est un écouteur de composant

Deadlock d’initialisation de GUI private static void createAndShowGUI() { … frame.pack(); frame.setVisible(true); } public static void main(String[] args) { createAndShowGUI(); public void componentResized (ComponentEvent e) { Afficher un texte dans un composant qui appartient a la frame. (trace de type JTextAera). } AWT-EventQueue-0 pack provoque des events componentResized. La méthode componentResized agit sur le composant JTextAera qui n’est pas encore visible. D’où l’interblocage (deadlock). Solution : il faut s’assurer que tous les composants sont visibles avant de lancer les évènements.

Pattern de création d’un GUI public static void main(String[] args) { SwingUtilities.invokeLater (new Runnable() { public void run() { createAndShowGUI(); } }); invokeLater (Runnable tache) est une méthode static de la classe SwingUtilities : Fera exécuter la méthode createAndshowGUI dans le thread event-dispatcher (AWT-EventQueue-0). Cette demande est ajoutée dans la file des événements en attente de traitement, comme il n’y a pas encore de composant, ce sera le premier traitement et ceci évite le deadlock. Cette méthode retourne immédiatement dans le thread appelant.

Tâche périodique dans un GUI Tâche à effectuer : déclencher un compte à rebours de 6 secondes. Toutes les secondes, il faut changer le label affiché et, à la fin, afficher fini. La tâche périodique est exécutée par un Timer Swing. Le Timer Swing se trouve dans javax.swing. Différent de Timer qui est dans java.util. Le constructeur Timer (period, listener) instancie un Timer de la période désirée avec un listener désigné. Aux instants ad-hoc, le timer enverra un événement ActionEvent au listener. La méthode setInitialDelay (délai) définit un délai initial avant l’établissement des périodes. La méthode setCoalesce (booléen) définit la politique du timer en cas d’encombrement : si true, et s’il y a plusieurs events à générer (du fait d’un retard), alors le timer n’envoie qu’un unique event.

Tâche périodique dans un GUI public void actionPerformed(ActionEvent e) { if (e.getActionCommand() != null) { boutonGo.setEnabled(false); compteur = 6; etatTachePeriodique.setText("reste "+ compteur +" secondes"); timer = new Timer(1000, this); /* chaque seconde, le timer envoie un événement à son écouteur */ timer.setInitialDelay(1000); // délai initial timer.setCoalesce(true); /* true, s’il y a plusieurs events à générer (encombrement), alors le timer n’envoie qu’un unique event*/ timer.start(); } else { // l’event de timer n'a pas de nom de commande ! if (--compteur <= -1) { timer.stop(); boutonGo.setEnabled(true); etatTachePeriodique.setText("fini !"); } else etatTachePeriodique.setText("reste "+compteur+" secondes"); } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() {new GUIetTachePeriodique8();} });} } import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTachePeriodique8 extends JFrame implements ActionListener { private JLabel etatTachePeriodique; private JButton boutonGo; private int compteur; private Timer timer; public GUIetTachePeriodique8() { super("GUIetTachePeriodique8"); Container contentPane = getContentPane(); boutonGo = new JButton("Demarrer"); contentPane.add(boutonGo,BorderLayout.NORTH); etatTachePeriodique = new JLabel ("pas de tache periodique"); contentPane.add(etatTachePeriodique,BorderLayout.CENTER); boutonGo.addActionListener(this); pack(); setVisible(true); }

Règle d’unicité du thread GUI Le modèle d’unicité du thread GUI : Tout le code qui affecte des composants Swing ou qui dépend de leurs états doit être exécuter par le thread event-dispatcher. A l’exception de quelques méthodes "thread-safe" de JComponent: repaint() : pour forcer le rafraîchissement de l’affichage d’un composant. revalidate() et invalidate() : pour forcer un composant à réorganiser ses enfants en fonction du layout choisi. invokeLater est une méthode "thread-safe".

Règle d’unicité du thread GUI import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTacheLongue3 extends JFrame implements ActionListener { JProgressBar barreProgression; JButton bouton; public GUIetTacheLongue3() { super("GUIetTacheLongue3"); Container contentPane = getContentPane(); barreProgression = new JProgressBar(); barreProgression.setMinimum(0); barreProgression.setMaximum(99); barreProgression.setValue(0); bouton = new JButton("Demarrer la tache longue"); contentPane.add(bouton,BorderLayout.NORTH); contentPane.add(barreProgression,BorderLayout.SOUTH); bouton.addActionListener(this); pack(); setVisible(true); } public void actionPerformed(ActionEvent e) { bouton.setEnabled(false); Thread t = new Thread() { public void run() { LongueTache3 tache = new LongueTache3(); tache.execute(); } }; t.start(); } Le constructeur AWT-EventQueue-0 Thread-3

Règle d’unicité du thread GUI class LongueTache3 { public void execute() { for (int i = 0; i < 100; i++ ) { setProgression(i); System.out.print("."); try {Thread.sleep (100);} catch (InterruptedException e) {} } System.out.println("") ; reset(); void setProgression (final int niveau ) { Runnable mettreAJourProgression = new Runnable() { public void run() { barreProgression.setValue (niveau); } }; SwingUtilities.invokeLater(mettreAJourProgression); } void reset() { Runnable remettreAZero = new Runnable() { barreProgression.setValue(0); bouton.setEnabled(true); SwingUtilities.invokeLater(remettreAZero); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new GUIetTacheLongue3(); } }); } AWT-EventQueue-0 Exécution:

Règle d’unicité du thread GUI Dans cet exemple, il y a 3 threads : main : réaliser les composants. AWT-EventQueue-0 : traiter les évènements. Thread-3 : réaliser la tâche longue. Les actions sur composants Swings sont tous dans le thread event dispatcher grâce à l’appel à la méthode invokeLater().

SwingWorker : tâche longue proprement import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTacheLongue4 extends JFrame implements ActionListener { JLabel etatLongueTache; JButton bouton; SwingWorker worker4; public GUIetTacheLongue4() { super ("GUIetTacheLongue4"); Container contentPane = getContentPane(); bouton = new JButton("Demarrer la tache longue"); contentPane.add(bouton,BorderLayout.NORTH); etatLongueTache = new JLabel("pas de Longue tache"); contentPane.add(etatLongueTache,BorderLayout.SOUTH); bouton.addActionListener(this); pack(); setVisible(true); } public void actionPerformed(ActionEvent e) { bouton.setEnabled(false); etatLongueTache.setText("tache en cours"); worker4 = new LongueTache4(); worker4.start(); class LongueTache4 extends SwingWorker { private int fin; public LongueTache4() { fin = (int)(Math.random()*100)+100; } public Object construct() { for(int i = 0; i < fin; i++ ) { System.out.print("."); try { Thread.sleep(100);} catch (InterruptedException e) {} } System.out.println("") ; return new Integer(fin); } public void finished() { bouton.setEnabled(true); etatLongueTache.setText("tache finie = " + fin); public static void main(String[] args) { SwingUtilities.invokeLater( new Runnable() { public void run() {new GUIetTacheLongue4();} }); } // fin de la classe GUIetTacheLongue4

SwingWorker : tâche longue proprement Dans cet exemple, la tâche n’affiche plus sa progression. La tâche est désormais une sous-classe de SwingWorker au lieu de Thread. SwingWorker permet d’implémenter facilement une tâche de fond dans un GUI. Son fonctionnement anciennement dans la méthode run() de Thread se retrouve dans la méthode construct() de SwingWorker. Elle est démarrée par start(), en plus dans finished(), se trouve le code à exécuter quand construct est terminé. Affichage du résultat de construct et réactivation du bouton stop.

SwingWorker : tâche longue proprement Il faut tout d’abord hériter de cette classe : Redéfinir la méthode construct() qui est l’équivalente de la méthode run(), mais retourne un Object. Sert typiquement à implémenter : De long calculs. Une attente bloquante sur entrée/sortie disque ou sur le net. Une attente de ressource. Eventuellement redéfinir la méthode finished() qui est appelée quand "construct" est terminée. Elle s’exécute sur le thread event-dispatcher et peut servir à implémenter les effets sur le GUI. La méthode start() permet de lancer l’exécution de contruct() dans un nouveau thread. Exécution:

SwingWorker : tâche longue avec interruption possible Désormais, un bouton permet d’interrompre (définitivement) la tâche longue. Exécution normale : Exécution avec interruption :

SwingWorker : tâche longue avec interruption possible public Object construct() { try { for(int i = 0; i < fin; i++ ) { System.out.print("."); Thread.sleep(100); } } catch (InterruptedException e) { System.out.println("interrupt !"); return new String("interrupt !"); } System.out.println("") ; return String.valueOf(fin); } public void finished() { boutonGo.setEnabled(true); boutonStop.setEnabled(false); String valeurFin = (String)get(); etatLongueTache.setText ("tache finie = " + valeurFin); } } // fin LongueTache5 public static void main(String[] args) { SwingUtilities.invokeLater( new Runnable() { public void run() { new GUIetTacheLongue5(); }); } import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTacheLongue5 extends JFrame implements ActionListener { JLabel etatLongueTache; JButton boutonGo; SwingWorker worker5; JButton boutonStop; public GUIetTacheLongue5() { super("GUIetTacheLongue5"); Container contentPane = getContentPane(); boutonGo = new JButton ("Demarrer la tache longue"); contentPane.add( boutonGo,BorderLayout.NORTH); boutonStop = new JButton("Stopper"); boutonStop.setEnabled(false); boutonStop.setBackground(Color.RED); boutonStop,BorderLayout.SOUTH); etatLongueTache = new JLabel("pas de Longue tache"); etatLongueTache,BorderLayout.CENTER); boutonGo.addActionListener(this); boutonStop.addActionListener(this); pack(); setVisible(true); } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals ("Demarrer la tache longue")) { boutonGo.setEnabled(false); boutonStop.setEnabled(true); etatLongueTache.setText ("tache en cours"); worker5 = new LongueTache5(); worker5.start(); } else { boutonStop.setEnabled(false); worker5.interrupt(); boutonGo.setEnabled(true); class LongueTache5 extends SwingWorker { private int fin; public LongueTache5() { fin = (int)(Math.random()*100)+100;

SwingWorker en interaction avec l’event-dispatcher Nous réintroduisons la barre de progression donc le thread SwingWorker a besoin de la mettre à jour. Celle-ci doit être manipulée dans le cadre du thread event-dispatcher d’où l’emploi d’invokeLater. Exécution :

SwingWorker en interaction avec l’event-dispatcher import java.awt.*; import java.awt.event.*; import javax.swing.*; public class GUIetTacheLongue6 extends JFrame implements ActionListener { JProgressBar barreProgression; JButton boutonGo; SwingWorker worker6; JButton boutonStop; public GUIetTacheLongue6() { super("GUIetTacheLongue6"); Container contentPane = getContentPane(); boutonGo = new JButton("Demarrer la tache longue"); contentPane.add(boutonGo,BorderLayout.NORTH); boutonStop = new JButton("Stopper"); boutonStop.setEnabled(false); boutonStop. setBackground(Color.RED); contentPane.add(boutonStop,BorderLayout.SOUTH); barreProgression = new JProgressBar(); barreProgression.setMinimum(0); barreProgression.setMaximum(99); barreProgression.setValue(0); contentPane.add(barreProgression,BorderLayout.CENTER); boutonGo.addActionListener(this); boutonStop.addActionListener(this); pack(); setVisible(true); } class LongueTache6 extends SwingWorker { public Object construct() { try { for(int i = 0; i < 100; i++ ) { System.out.print("."); setProgression(i); Thread.sleep(100); } } catch (InterruptedException e) { System.out.println("interrupt !"); return new String("interrupt !"); } System.out.println("") ; return new String("tache accomplie"); } public void finished() { boutonGo.setEnabled(true); boutonStop.setEnabled(false); } // fin LongueTache6 public static void main(String[] args) { SwingUtilities.invokeLater( new Runnable() { public void run() { new GUIetTacheLongue6(); }); } // fin GUIetTacheLongue6 public void actionPerformed (ActionEvent e) { if (e.getActionCommand().equals("Demarrer la tache longue")) { boutonGo.setEnabled(false); boutonStop.setEnabled(true); barreProgression.setValue(0); worker6 = new LongueTache6(); worker6.start(); } else { boutonStop.setEnabled(false); worker6.interrupt(); boutonGo.setEnabled(true); void setProgression (final int niveau) { Runnable mettreAJour = new Runnable() { public void run() { barreProgression.setValue(niveau); }; SwingUtilities.invokeLater(mettreAJour);