Bonjour,
Il s'agit d'un problème faisant suite à 1 discussion précédente, que je délocalise, pour ne pas polluer le sujet initial de l'auteur (voir
Actions concurrentes dans l'EDT)
Le sujet est assez simple, et la solution doit l'être tout autant...
mais pour l'instant, je ne l'ai pas trouvée.
Il s'agit d'exécuter une action longue dans Swing, sans bloquer l'EDT, et en donnant la possibilité à l'utilisateur :
- de démarrer la tâche longue
- de la mettre en pause ou de la reprendre
- de la stopper définitivement
J'ai une classe permettant de gérer ce type de tâche, mal, puisque la méthode sensée mettre la tâche en pause bloque l'EDT (
méthode sleep en rouge)
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
|
public abstract class MyTask implements Runnable {
private int delai = 1000;
private volatile Thread currentThread = null;
public void run() {
currentThread = Thread.currentThread();
while (!currentThread.isInterrupted() && continueCondition()) {
doMyTask();
try {
Thread.sleep(delai);
} catch (InterruptedException exception) {
onCancelled();
break;
}
}
}
public void cancel() {
currentThread.interrupt();
}
//Pose problème : méthode bloquant l'EDT
public void sleep() {
synchronized (this) {
try {
while (!currentThread.isInterrupted()) {
this.wait();
}
} catch (InterruptedException e) {
onCancelled();
}
}
}
public void wakeUp() {
synchronized (this) {
this.notify();
}
}
public abstract void doMyTask();
public abstract boolean continueCondition();
public abstract void onCancelled();
} |
- doMyTask permet d'implémenter 1 tâche atomique (1 parcours de boucle...)
- continueCondition est ta condition de continuité (de la boucle par exemple)
- onCancelled, la méthode à implémenter en cas d'annulation
Ci dessous une classe de test implémentant
MyTask (avec une tâche bidon consistant à boucler...):
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
public class TestThreads extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JPanel mainPanel;
private JButton btStart;
private JButton btStop;
private JButton btSleep;
private JButton btWakeUp;
private MyTask mytask;
private Thread currentThread;
private JLabel lblCompteur;
private int compteur = 0;
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
private TestThreads t;
@Override
public void run() {
t = new TestThreads();
}
});
}
public TestThreads() {
super();
// Tâche
mytask = new MyTask() {
@Override
public void onCancelled() {
compteur = 0;
updateLblCompteur();
}
@Override
public void doMyTask() {
compteur++;
updateLblCompteur();
};
@Override
public boolean continueCondition() {
return compteur < 10000;
}
};
// Fenêtre
JFrame fen = new JFrame("Test threads");
fen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fen.setLayout(new BorderLayout());
mainPanel = new JPanel(new FlowLayout());
lblCompteur = new JLabel("0");
mainPanel.add(lblCompteur);
btStart = getButton("Start");
btStop = getButton("Stop");
btSleep = getButton("Sleep");
btWakeUp = getButton("Reveil");
fen.add(mainPanel, BorderLayout.NORTH);
fen.pack();
fen.setVisible(true);
}
/**
* Création d'un bouton
*
* @param text
* @return
*/
private JButton getButton(String text) {
JButton bt = new JButton(text);
bt.addActionListener(this);
mainPanel.add(bt);
return bt;
}
private void updateLblCompteur() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
lblCompteur.setText(compteur + "");
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(btStart)) {
currentThread = new Thread(mytask);
currentThread.start();
}
if (e.getSource().equals(btStop))
mytask.cancel();
if (e.getSource().equals(btSleep)) {
// Problème !!!!!!!!! Méthode bloquante
mytask.sleep();
System.out.println("pas sleep");
}
if (e.getSource().equals(btWakeUp))
mytask.wakeUp();
}
} |
Logiquement, le thread de la tâche n'est pas lancé dans l'EDT :
1 2 3
|
currentThread = new Thread(mytask);
currentThread.start(); |
donc pourquoi le wait sur mytask bloque t-il l'EDT ?
Partager