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

EDT/SwingWorker Java Discussion :

[EDT et MVC] Affichage après processus


Sujet :

EDT/SwingWorker Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Janvier 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Janvier 2010
    Messages : 32
    Par défaut [EDT et MVC] Affichage après processus
    Bonjour à tous,


    Je suis en train de coder une petite application basée sur un MVC classique et basique. Mon interface graphique est composée d'un panel gauche contenant un JTree et d'un panel droit de type JTabbedPane contenant lui-même des JTabbedPane.

    Chaque feuille du JTree représente un scénario de test. Chaque test est composé de plusieurs processus. Lors de l'exécution d'un scénario, un nouveau JTabbedPane "nom du scénario" est créé et dans celui-ci, un nouveau JTabbedPane est créé pour chaque nouveau processus démarré.

    Mon problème se situe au niveau de l'affichage des résultats de chaque processus : j'aimerais que celui-ci se fasse en direct, à la volée, alors qu'avec mon code actuel, les résultats sont affichés en une fois à la fin du processus.
    C'est assez embêtant car si un processus prend plusieurs minutes, je n'ai aucune idée de son avancement...

    Humblement, je pense qu'il s'agit d'un problème avec l'EDT qui ne reprend la main qu'à la fin de chaque processus et ne fait donc son boulot (i.e. afficher) qu'une fois le thread du processus terminé.

    Voici les différentes classes :

    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
    public class MyApplicationGUI extends MyApplicationView implements ActionListener {
     
        private JFrame mainFrame = null;
        private JTabbedPane rightPane = null;
        private JTree tree;
        private PrintWriter guiPrintWriter = null;
     
     
        /**
         * 
         * @param controller
         */
        public MyApplicationGUI(MyApplicationController controller){
            super(controller); 
     
            // Setup the frame, panels, menu, etc...
            buildFrame();
        }
     
        ...
     
        /**
         * 
         * @return
         */
        @Override
        public PrintWriter getGuiPrintWriter() {
            return guiPrintWriter;
        }
     
        ...
     
    public void currentScenarioChanged(CurrentScenarioChangedEvent event) {
            String newScenarioName = event.getNewCurrentScenarioName();
     
            int index = rightPane.indexOfTab(newScenarioName);
     
            if (index != -1) {
                closeScenarioTabAtIndex(index);
            }
     
            JTabbedPane newScenPane = new JTabbedPane();
     
            rightPane.add(newScenarioName, newScenPane);
            rightPane.setSelectedComponent(newScenPane);
        }
     
     
        /**
         * New process means new sub-tab to be opened under the corresponding 
         * scenario tab in the right pane.
         * 
         * @param event
         */
        public void processChanged(ProcessChangedEvent event) {
            String currentScenarioName = event.getCurrentScenarioName();
            String newProcessName = event.getNewProcess();
     
            // Retrieve the JTabbedPane of the scenario (should be the one active)
            JTabbedPane scenTabPane = getScenarioTabbedPane(currentScenarioName);
     
            // Close the previous stream if any
            if (guiPrintWriter != null) {
                guiPrintWriter.close();
            }
     
            if (scenTabPane != null) {
                LogPane pane = new LogPane();
                scenTabPane.add(newProcessName, pane.getPanel());
                scenTabPane.setSelectedComponent(pane.getPanel());
                guiPrintWriter = new PrintWriter(pane, true);
            }
        }
     
    	...
     
        private JTabbedPane getScenarioTabbedPane(String scenarioName) {
            return (JTabbedPane) rightPane.getComponentAt(rightPane.indexOfTab(scenarioName));
        }
     
    }
    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
    public class MyApplicationModel {
        private Scenario currentScenario;
        private EventListenerList listeners;
     
        public MyApplicationModel(){
            super();
     
            this.currentScenario = null;
     
            listeners = new EventListenerList();
        }
     
        public void setCurrentScenario(Scenario theCurrentScenario) {
            currentScenario = theCurrentScenario;
     
            fireCurrentScenarioChanged();
        }
     
        public void fireCurrentScenarioChanged(){
            MyApplicationListener[] listenerList = (MyApplicationListener[])listeners.getListeners(MyApplicationListener.class);
     
            for (MyApplicationListener listener : listenerList){
                listener.currentScenarioChanged(new CurrentScenarioChangedEvent(this, getCurrentScenario().getScenarioName()));
            }
        }
     
    }
    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
    public class MyApplicationController {
        public MyApplicationView maGUI = null;
        private MyApplicationModel maModel = null;
     
        ...
     
        public MyApplicationController (MyApplicationModel model) {
            this.maModel = model;
     
            maGUI = new MyApplicationGUI(this);
     
            addListenersToModel();
        }
     
        ...
     
        public void notifyMyApplicationChanged(ActionEvent evnt) {
            ...
     
            Scenario monScenario = new Scenario(maGUI.getSelectedScenario());
     
            model.setCurrentScenario(monScenario);
     
            executionMode1(monScenario);
        }
     
        private void executionMode1(Scenario currentScenario) {
            String scenarioName = currentScenario.getScenarioName();
     
            Collection<ScenarioProcess> scenarioProcesses = currentScenario.getScenarioProcesses();
     
            for (ScenarioProcess currentProcess : scenarioProcesses) {
                String processName = currentProcess.getProcessName();
     
                model.setCurrentProcess(processName);
     
                ScenarioProcessFactory scenarioProcessFactory = ScenarioProcessFactory.newInstance();
                ScenarioProcessInterface scenarioProcess = scenarioProcessFactory.createScenarioProcess(currentProcess.getProcessType());
     
                if (scenarioProcess != null) {
                    if (!scenarioProcess.execute(scenarioName, currentProcess.getScenarioData(), maGUI.getGuiPrintWriter())) {
                        // Put the current sub-tab in red and go on with the next processes
                        maGUI.scenarioProcessFailure(scenarioName, processName);
                    }
                }
            }
        }
     
    }
    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
    public class Process1 implements ScenarioProcessInterface {
     
        private PrintWriter process1PrintWriter = null;
     
    	...
     
        public synchronized boolean execute(String scenarioName, Collection<ScenarioData> scenarioData, PrintWriter guiPrintWriter) {
            this.process1PrintWriter = guiPrintWriter;
     
            ...
     
    		process1PrintWriter.println("Start of the execution...");
     
    		...
     
    		process1PrintWriter.println("End of the execution...");
    	}
     
    }
    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
    public class LogPane extends OutputStream {
        private JTextArea mainTextArea;
        private JPanel mainPanel;
        private StringBuffer sb = new StringBuffer(255);
     
     
        public LogPane() {
            JScrollPane mainScrollingPane;
     
            mainPanel = new JPanel(new java.awt.BorderLayout());
            mainTextArea = new JTextArea();
            mainScrollingPane = new JScrollPane(mainTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            mainScrollingPane.setWheelScrollingEnabled(true);
            mainPanel.add(mainScrollingPane, java.awt.BorderLayout.CENTER);
            mainTextArea.setEditable(false);
        }
     
     
        public JPanel getPanel() {
            return mainPanel;
        }
     
     
        public void set(String text) {
            mainTextArea.setText(text);
            mainTextArea.setCaretPosition(mainTextArea.getText().length());
        }
     
     
        public void append(String text) {
            mainTextArea.append(text);
            mainTextArea.setCaretPosition(mainTextArea.getText().length());
        }
     
     
        public void clear() {
            mainTextArea.setText("");
        }
     
     
        public JTextArea getMainTextArea() {
            return mainTextArea;
        }
     
     
        public String getSelection() {
            return mainTextArea.getSelectedText();
        }
     
     
        public void write(int b) throws IOException {
            Integer i = Integer.valueOf(b);
            char c = (char) i.byteValue();
            sb.append(c);
            if (c == '\n' || sb.length() == 255) {
                flush();
            }
        }
     
     
        public void flush() throws IOException {
            append(sb.toString());
            sb = sb.delete(0, sb.length());
        }
     
     
        public void close() throws IOException {
            flush();
        }
     
    }
    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
     
    public class CurrentScenarioChangedEvent extends EventObject {
        private static final long serialVersionUID = 1L;
        private String newCurrentScenarioName;
     
        public CurrentScenarioChangedEvent(Object source, String aNewCurrentScenarioName){
            super(source);
     
            this.newCurrentScenarioName = aNewCurrentScenarioName;
        }
     
        public String getNewCurrentScenarioName(){
            return newCurrentScenarioName;
        }
     
    }
    Bref, lorsqu'un nouveau scénario est exécuté, le controleur notifie le modèle qui lui-même notifie la vue. Cette dernière devrait donc créer un nouveau JTabbedPane AVANT d'appeler executionMode1 ! Mais ce n'est pas le cas...

  2. #2
    Membre averti
    Inscrit en
    Janvier 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Janvier 2010
    Messages : 32
    Par défaut
    Du neuf par rapport à mon problème !

    J'ai créé une nouvelle classe ScenarioThread (qui étend Thread) et dans la méthode run(), j'ai coupé/collé le contenu de la méthode executionMode1 de mon contrôleur. A la place, je crée un objet ScenarioThread et j'appelle simplement start() dessus. Rien de bien compliqué et ça marche nickel !

    Cependant, le code de mon contrôleur a changé entretemps. Il doit être capable de gérer l'exécution de plusieurs scénarios de test :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void notifyMyApplicationChanged(ActionEvent evnt) {
            TreePath[] selectedScenPaths = maGUI.getNamesOfSelectedScenarios();
     
            for (TreePath selectedScenPath : selectedScenPaths) {
                Scenario monScenario = new Scenario(selectedScenPath.getLastPathComponent().toString());
     
                model.setCurrentScenario(monScenario);
     
                executionMode1(monScenario);
            }
        }
    Et dans le cas ou je veux exécuter plusieurs scénarios, ça foire à nouveau puisqu'il n'y a pas de synchro : l'exécution du premier scénario démarre puis directement le suivant qui vient en conflit avec le premier, et ainsi de suite...

    Est-ce que le SwingWorker devient nécessaire ou est-ce que je peux encore "jouer" avec les méthodes de Thread (isAlive(), etc...) ?

    Merci !

  3. #3
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    SwingWorker est là pour simplifier la création de tâche en arrière plan, donc je ne vois pas de raison de continuer à gérer ses threads manuellement...


    Pour le reste, je n'ai pas vraiment compris à quel niveau se situe le problème.

    a++

  4. #4
    Membre averti
    Inscrit en
    Janvier 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Janvier 2010
    Messages : 32
    Par défaut
    Maintenant, le problème est le suivant : sachant que la méthode executionMode1 va créer un Thread séparé pour le processus d'un scénario de test, comment puis-je savoir que ce thread a terminé et ainsi pouvoir passer (dans la boucle for (TreePath...) ) au processus du scénario suivant ?

  5. #5
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Il suffit de créer des SwingWorker et de les passer à un executor mono-thread. Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	// On crée un executor mono-thread :
    	ExecutorService executor = Executors.newFixedThreadPool(1);
     
    	for (...) {
    		// On crée toutes nos tâches :
    		SwingWorker<?, ?> task = ...;
    		// Que l'on lance via notre executor
    		executor.submit(task);
    	}
    Comme on utilises un seul thread, les différentes tâches seront exécutées une après l'autre.

    a++

  6. #6
    Membre averti
    Inscrit en
    Janvier 2010
    Messages
    32
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Janvier 2010
    Messages : 32
    Par défaut
    Oh, désolé, je ne connaissais pas ExecutorService...

    Effectivement, avec ton code, j'ai exactement ce qu'il me faut ! Un grand merci mon Cher.

    Question subsidiaire : admettons que j'aie besoin de la valeur de retour (un simple booléen) du processus exécuté en background afin de savoir si je dois sortir de ma boucle ou pas.

    J'ai essayé avec le code suivant :
    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
    public void notifyMyApplicationChanged(ActionEvent evnt) {
            TreePath[] selectedScenPaths = maGUI.getNamesOfSelectedScenarios();
     
            ExecutorService executor = Executors.newFixedThreadPool(1);
     
            for (TreePath selectedScenPath : selectedScenPaths) {
                Scenario monScenario = new Scenario(selectedScenPath.getLastPathComponent().toString());
     
                ScenarioTask scenarioTask = new ScenarioTask(...);
     
                Future taskResult = executor.submit(scenarioTask);
     
                try {
                    if (Boolean.FALSE.equals((Boolean)taskResult.get())) {
                        break;
                    }
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                } catch (ExecutionException ee) {
                    ee.printStackTrace();
                }
            }
     
            executor.shutdown();
        }
    Malheureusement, l'affichage se fait à nouveau à la toute fin du scénario...

    Est-ce que je dois plutôt utiliser la valeur de retour de la méthode doInBackground ???

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

Discussions similaires

  1. Problème d'affichage après un tri....
    Par lyim dans le forum Langage
    Réponses: 4
    Dernier message: 27/04/2006, 18h06
  2. [Menu] Problème d'affichage après redirection
    Par Pfeffer dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 22/03/2006, 22h04
  3. [PowerBuilder] Prob. d'affichage après insertion de contrôle
    Par Oakenshield dans le forum Powerbuilder
    Réponses: 1
    Dernier message: 30/01/2006, 15h37
  4. Réponses: 5
    Dernier message: 29/07/2005, 10h00
  5. Pb d'affichage apres une liste déroulante
    Par loic.440 dans le forum ASP
    Réponses: 13
    Dernier message: 19/01/2005, 15h28

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