La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Badr Benmammar Thread et Swing.

Présentations similaires


Présentation au sujet: "Badr Benmammar Thread et Swing."— Transcription de la présentation:

1 Badr Benmammar Thread et Swing

2 Plan Tâche longue dans un une interface utilisateur graphique (GUI ) Deadlock dinitialisation de GUI Pattern de création dun GUI Tâche périodique dans un GUI Règle dunicité du thread GUI Class SwingWorker : tâche longue proprement Tâche longue avec interruption possible Interaction avec levent-dispatcher

3 Tâche longue dans un GUI Problème : exécuter une tâche relativement longue dans le cadre dune (GUI) interface graphique pour lutilisateur. La tâche dure quelques secondes voire des minutes. Linterface doit pouvoir encore réagir aux actions de lutilisateur. 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.

4 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(); } } 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("") ; } La tâche longue Classe interne anonyme pour installer un écouteur correspond au composant bouton

5 Tâche longue dans un GUI $ Remarque : Arrêtez avec car la fermeture de la fenêtre et larrêt de lappli 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 nest mise à jour quà la fin ! Exécution:

6 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 dimplémenter le thread.

7 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.

8 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

9 Utilitaire pour tracer les threads Ce code sexécute sur 2 threads : main pour pack, setVisible (réaliser les composants). AWT-EventQueue-0 pour laction (les événements). Swing (et AWT) dispose dun thread spécifique pour traiter les événements : levent 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.

10 Deadlock dinitialisation 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(); } Cest un écouteur de composant

11 Deadlock dinitialisation 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). } pack provoque des events componentResized. La méthode componentResized agit sur le composant JTextAera qui nest pas encore visible. Doù linterblocage (deadlock). Solution : il faut sassurer que tous les composants sont visibles avant de lancer les évènements. AWT-EventQueue-0

12 Pattern de création dun 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 ny 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.

13 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 dencombrement : si true, et sil y a plusieurs events à générer (du fait dun retard), alors le timer nenvoie quun unique event.

14 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); } 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, sil y a plusieurs events à générer (encombrement), alors le timer nenvoie quun unique event*/ timer.start(); } else { // levent 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();} });} }

15 Règle dunicité du thread GUI Le modèle dunicité 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 lexception de quelques méthodes "thread-safe" de JComponent: repaint() : pour forcer le rafraîchissement de laffichage dun composant. revalidate() et invalidate() : pour forcer un composant à réorganiser ses enfants en fonction du layout choisi. invokeLater est une méthode "thread-safe".

16 Règle dunicité 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(); } AWT-EventQueue-0 Thread-3 Le constructeur

17 Règle dunicité 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() { public void run() { barreProgression.setValue(0); bouton.setEnabled(true); } }; SwingUtilities.invokeLater(remettreAZero); } AWT-EventQueue-0 public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { new GUIetTacheLongue3(); } }); } Exécution:

18 Règle dunicité 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 à lappel à la méthode invokeLater().

19 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

20 SwingWorker : tâche longue proprement Dans cet exemple, la tâche naffiche plus sa progression. La tâche est désormais une sous-classe de SwingWorker au lieu de Thread. SwingWorker permet dimplé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.

21 SwingWorker : tâche longue proprement Il faut tout dabord 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 sexécute sur le thread event-dispatcher et peut servir à implémenter les effets sur le GUI. La méthode start() permet de lancer lexécution de contruct() dans un nouveau thread. Exécution:

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

23 SwingWorker : tâche longue avec interruption possible 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); contentPane.add( boutonStop,BorderLayout.SOUTH); etatLongueTache = new JLabel("pas de Longue tache"); contentPane.add( 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; } 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(); } }); } }

24 SwingWorker en interaction avec levent-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 doù lemploi dinvokeLater. Exécution :

25 SwingWorker en interaction avec levent-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); } 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); } 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


Télécharger ppt "Badr Benmammar Thread et Swing."

Présentations similaires


Annonces Google