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

AWT/Swing Java Discussion :

EDT: fenetre qui ne se ferme pas


Sujet :

AWT/Swing Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    546
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 546
    Par défaut EDT: fenetre qui ne se ferme pas
    Bonjour,

    J'ai écrit un programme java dans lequel je fais un certain nombre de calculs qui peuvent prendre du temps.
    Du coup, le temps des calculs, je "disable" mon interface et j'affiche une fenêtre modal "dialogWIP" que je ferme et je "enable" l'interface quand le calcul est fini.
    Ca fonctionne, sauf que parfois, si le calcul est très rapide, ma fenêtre ne se ferme pas, par contre mon interface se met bien en "enable".
    Je fais les affichage dans l'EDT mais on dirait qu'il se mélange les pinceaux et qu'il n’exécute pas les ordres dans l'ordre.
    Voici mon code
    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
     
        jControleur = new ControleAppli();
        jControleur.start();
     
        protected class ControleAppli extends Thread {
    	JOptionPane messagePane = new JOptionPane("Work in progress, please wait...", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[]{}, null);
    	JDialog dialogWIP = messagePane.createDialog(null, "Processing");
     
            public void run() {
                SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                // disable interface
                                dialogWIP.setVisible(true);
                            }
                        });
     
     
                // je fais les calculs
     
                SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                // enable interface
                                dialogWIP.setVisible(false);
                            }
                        });
            }
        }
    J'ai trouvé une parade en faisant une "pause" de 1 seconde avant de rendre la main dans le cas ou le calcul serait trop rapide, mais bon c'est pas terrible comme solution.

    Pourquoi ça fait cela ?
    Merci de votre aide.

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Salut,

    Au lieu de chercher à bidouiller ce genre de choses avec des invokeLater, dont tu ne pourras pas contrôler facilement le moment d'exécution, tu devrais utiliser un SwingWorker qui te facilitera ce genre de chose : avant de lancer le SwingWorker, donc depuis l'EDT, tu disables ton interface, tu affiches ton dialogue d'attente, qui ne devrait pas être modal (car metteras en attente l'appelant), et dans la méthode done() du SwingWorker, tu ferme ton dialogue (attention setVisible(false) cache une fenêtre, c'est dispose() pour la fermer), et rétablis l'interface.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    546
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 546
    Par défaut
    Merci de ton retour.
    J'ai étudié le SwingWorker en regardant le tuto ici : http://rom.developpez.com/java-swingworker/
    Du coup j'ai déplacé tous mes calculs dans la méthode doInBackground().
    Par contre j'ai une question, en fait on ne fait plus qu'un seul appel à invokeLater() dans lequel on appelle le execute() du swingWorker ? Ensuite il va exécuter la méthode doInBackground() du swingWorker et quand il aura fini il appellera la méthode done(), c'est bien ça ?
    Parce que dans mon calcul je faisais des rafraîchissements de l'interface (je change le contenu d'une JList par exemple) et je faisais ces appels dans un invokeLater(). Du coup, je n'ai plus besoin de les faire dans un invokeLater(), je fais mes modifs directement dans le doInBackground()...?

    Enfin, dernière question, avec le swingWorker, je n'ai plus de problème d'affichage de ma fenêtre, elle s'affiche et s'enlève comme il faut, même si le calcul est rapide. Par contre mon "disable" de l'interface ne se fait pas, comment ça se fait ?
    Pour cette dernière question, j'ai trouvé, c'était un appel qui manquait dans mon code, tout va bien...

    Merci de votre aide.

  4. #4
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par jejeman Voir le message
    Par contre j'ai une question, en fait on ne fait plus qu'un seul appel à invokeLater() dans lequel on appelle le execute() du swingWorker ?
    A priori, on devrait même pas faire d'invokeLater : l'exécution est lancée par un bouton ou autre composant d'UI non ?

    Citation Envoyé par jejeman Voir le message
    Ensuite il va exécuter la méthode doInBackground() du swingWorker et quand il aura fini il appellera la méthode done(), c'est bien ça ?
    Oui en gros c'est ça.

    Citation Envoyé par jejeman Voir le message
    Parce que dans mon calcul je faisais des rafraîchissements de l'interface (je change le contenu d'une JList par exemple) et je faisais ces appels dans un invokeLater(). Du coup, je n'ai plus besoin de les faire dans un invokeLater(), je fais mes modifs directement dans le doInBackground()...?
    Les modifications d'UI relatives aux traitements doivent être faites dans la méthode process() de SwingWorker.

    Le principe c'est que dans doInBackground() tu génères des données destinées à être affichées : tu utilises la méthode publish() pour dire que tu les publies, ensuite la méthode process() sera déclenchée au moment opportun et s'exécutera dans l'EDT, ce qui te permettra de faire la mise à jour de ton UI.

    Exemple :
    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
    public class SwingWorkerExample {
     
    	public static void main(String[] args) {
     
    		JFrame frame = new JFrame("Démo");
    		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     
    		JPanel panel = new JPanel(new BorderLayout());
     
    		JList<String> list = new JList<>(new DefaultListModel<>());
    		panel.add(new JScrollPane(list));
     
    		JLabel label = new JLabel();
    		panel.add(label, BorderLayout.NORTH);
     
    		JButton button = new JButton("Lancer...");
    		panel.add(button, BorderLayout.SOUTH);
     
    		button.addActionListener(e-> launchTask(button, label, list));
     
    		frame.add(panel);
     
    		frame.setSize(400, 300);
    		frame.setLocationRelativeTo(null);
    		frame.setVisible(true);
     
     
    	}
     
    	private static void launchTask(JButton button, JLabel label, JList<String> list) {
    		button.setEnabled(false);
    		label.setText("Traitement...");
    		((javax.swing.DefaultListModel<String>)list.getModel()).removeAllElements();
    		new SwingWorker<Integer, String>() {
     
    			@Override
    			protected Integer doInBackground() throws Exception {
    				int nb=ThreadLocalRandom.current().nextInt(30,50);
    				for(int i=0; i<nb; i++) {
    					Thread.sleep(1000); // simule un temps long pour produire la donnée
    					publish(String.valueOf(i+1)); // produit la donnée
    				}
    				return nb; 
    			}
     
    			@Override
    			protected void process(List<String> chunks) {
    				// affiche les dernières données produites
    				for(String chunk : chunks) {
    					((javax.swing.DefaultListModel<String>)list.getModel()).addElement(chunk);
    				}
    			}
     
    			@Override
    			protected void done() {
    				try {
    					label.setText("Nb : " + get());
    				} catch (InterruptedException | ExecutionException e) {
    					e.printStackTrace();
    					label.setText("Erreur!");
    				}
    				button.setEnabled(true);
    			}
     
    		}.execute(); 
    	}
     
    }
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  5. #5
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    546
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France

    Informations forums :
    Inscription : Mars 2005
    Messages : 546
    Par défaut
    Je me permets de reprendre mon sujet, car je me remets dessus...
    Donc si j'ai bien tout compris:
    - on utilise doInBackground() pour faire les calculs
    - en background je fais des publish() si je veux produire des résultats intermédiaires pour mon interface
    - la méthode process() est appelée de temps en temps dans le thread EDT et prends en paramètre les infos qui ont été publish(). Question: elle prend les infos dans l'ordre de leur publish() ?
    - la méthode done() est appelée dans le thread EDT quand doInBackground() a fini

    Du coup il me reste une question.
    Dans mon cas, avant d'appeler le doInBackground() qui va faire mes traitements, je veux afficher une fenêtre qui va dire "patientez..."
    Comment j'appelle cette fenêtre ? Dans un invokeLater() ? Au tout début du doInBackground() ? Avant l'appel au doInBackground() ?
    Dans ce cas, l'appel à l'affichage de la fenêtre sera bien réalisé avant le done() ?

    En ce qui concerne le "dispose" de cette fenêtre, là c'est clair, je le fais dans le done().

    Merci de votre retour.

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par jejeman Voir le message
    - la méthode process() est appelée de temps en temps dans le thread EDT et prends en paramètre les infos qui ont été publish(). Question: elle prend les infos dans l'ordre de leur publish() ?
    La documentation ne précise rien au sujet de l'ordre, donc aucune garantie de ça (tout ce que dit la doc, c'est que plusieurs appels de publish() peuvent être regroupés dans un appel de process().

    Citation Envoyé par jejeman Voir le message
    Du coup il me reste une question.
    Dans mon cas, avant d'appeler le doInBackground() qui va faire mes traitements, je veux afficher une fenêtre qui va dire "patientez..."
    Comment j'appelle cette fenêtre ? Dans un invokeLater() ? Au tout début du doInBackground() ? Avant l'appel au doInBackground() ?
    Tout d'abord, il n'y a pas à invoquer doInBackground(), mais on appelle execute() de SwingWorker, qui se débrouille ensuite. Donc tu peux ouvrir ta fenêtre avant d'appeller execute(),
    Citation Envoyé par jejeman Voir le message
    En ce qui concerne le "dispose" de cette fenêtre, là c'est clair, je le fais dans le done().
    Oui, ou par écouteur :
    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
     
    worker.addPropertyChangeListener(new PropertyChangeListener() {
     
    			JFrame frame = new JFrame();
    			{
    				frame.setSize(300, 400);
    				frame.setLocationRelativeTo(null);
    			}
    			@Override
    			public void propertyChange(PropertyChangeEvent evt) {
    				if ( "state".equals(evt.getPropertyName()) ) {
    					switch((SwingWorker.StateValue)evt.getNewValue()) {
    					case STARTED:
    						frame.setVisible(true);
    						break;
    					case DONE:
    						frame.dispose();
    						break;
    					}
    				}
    			}
    		});
    worker.execute();
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

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

Discussions similaires

  1. [WD11] Fenetre qui ne s'ouvre pas
    Par hegros dans le forum WinDev
    Réponses: 29
    Dernier message: 27/03/2007, 11h33
  2. Fenetre qui ne s'ouvre pas
    Par Anduriel dans le forum Général JavaScript
    Réponses: 11
    Dernier message: 29/06/2006, 11h23
  3. Formulaire qui ne se ferme pas.
    Par Smint dans le forum Access
    Réponses: 7
    Dernier message: 02/06/2006, 10h34
  4. [VB6]Process qui ne se ferme pas
    Par marsup54 dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 19/04/2006, 13h57
  5. [FORMS] Form qui ne se ferme pas
    Par MxPx_23 dans le forum Oracle
    Réponses: 4
    Dernier message: 08/12/2005, 07h29

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