Article de reference

Fil de discussion sur la répartition des événements

Le thread de répartition d'événements (EDT) est un thread d'arrière-plan utilisé en Java pour traiter les événements de la file d'attente d'événements de l' interface utilisateu...

Le thread de répartition d'événements (EDT) est un thread d'arrière-plan utilisé en Java pour traiter les événements de la file d'attente d'événements de l' interface utilisateur graphique AWT ( Abstract Window Toolkit ) . Il s'agit d'un exemple du concept générique de programmation pilotée par événements , qui est populaire dans de nombreux autres contextes que Java, par exemple, les navigateurs Web ou les serveurs Web .

Les événements sont principalement des événements de mise à jour qui provoquent le redessin des composants de l'interface utilisateur ou des événements d'entrée provenant de périphériques d'entrée tels que la souris ou le clavier. L'AWT utilise un modèle de peinture à thread unique dans lequel toutes les mises à jour d'écran doivent être effectuées à partir d'un seul thread. Le thread de distribution d'événements est le seul thread valide pour mettre à jour l'état visuel des composants d'interface utilisateur visibles. La mise à jour des composants visibles à partir d'autres threads est la source de nombreux bogues courants dans les programmes Java qui utilisent Swing . Le thread de distribution d'événements est appelé le travailleur primordial dans Adobe Flash et le thread d'interface utilisateur dans SWT , .NET Framework et Android .

Boucle de message pour la sérialisation des accès à l'interface graphique

Une application logicielle se compose normalement de plusieurs threads et d'une seule structure de données GIT. Cela signifie que GIT est une structure de données partagée et qu'une certaine synchronisation est nécessaire pour garantir qu'un seul thread y accède à la fois. Bien qu'AWT et Swing exposent les méthodes ( thread unsafe ) pour créer et accéder aux composants de l'interface utilisateur graphique et que ces méthodes soient visibles par tous les threads d'application, de même dans d'autres frameworks d'interface utilisateur graphique, un seul thread de répartition d'événements a le droit d'exécuter ces méthodes. les Look and Feels tiers , comme Substance, vont jusqu'à refuser d'instancier tout composant Swing lorsqu'il n'est pas exécuté dans le thread de répartition d'événements, pour éviter une telle erreur de codage. L'accès à l'interface utilisateur graphique est sérialisé et d'autres threads peuvent soumettre du code à exécuter dans l'EDT via une file d'attente de messages EDT .

Autrement dit, comme dans d'autres frameworks d'interface utilisateur graphique, le thread de répartition des événements passe sa vie à pomper des messages : il maintient une file d'attente de messages d'actions à exécuter sur l'interface utilisateur graphique. Ces requêtes sont soumises à la file d'attente par le système et par tout thread d'application. EDT les consomme les unes après les autres et répond en mettant à jour les composants de l'interface utilisateur graphique. Les messages peuvent être des actions bien connues ou impliquer des rappels, des références à des méthodes utilisateur qui doivent être exécutées au moyen d'EDT.

L'exigence importante imposée à tous les messages est qu'ils doivent être exécutés rapidement pour que l'interface graphique reste réactive. Dans le cas contraire, la boucle de messages est bloquée et l'interface graphique se bloque.

Soumission du code utilisateur à l'EDT

Il existe différentes solutions pour soumettre du code à l'EDT et effectuer des tâches longues sans bloquer la boucle.

Gestionnaires d'événements de composants (écouteurs)

Les composants de l'interface utilisateur graphique prennent en charge les listes de rappels, appelées Listeners, qui sont généralement renseignées lors de la création des composants. EDT exécute les écouteurs lorsque l'utilisateur active les composants d'une manière ou d'une autre (un bouton est cliqué, la souris est déplacée, un élément est sélectionné, le focus est perdu, le composant est redimensionné, etc.).

Minuteur

Pour les tâches courtes qui doivent accéder à l'interface graphique ou la modifier périodiquement ou à un moment précis, javax.swing.Timeril est utilisé. Il peut être considéré comme un composant d'interface graphique invisible, dont les écouteurs sont enregistrés pour se déclencher à des moments précis.

Equivalents

Demandes provenant d'autres threads

D'autres threads d'application peuvent transmettre du code à exécuter dans le thread de distribution d'événements au moyen de SwingUtilitiesclasses d'assistance (ou EventQueuesi vous utilisez AWT ). Le code soumis doit être enveloppé dans un Runnableobjet. Deux méthodes de ces classes permettent :

  • exécution de code synchrone ( SwingUtilities.invokeAndWait(Runnable)ou EventQueue.invokeAndWait(Runnable))
  • et l'exécution de code asynchrone ( SwingUtilities.invokeLater(Runnable)ou EventQueue.invokeLater(Runnable))

à partir du thread de répartition des événements.

La méthode invokeAndWait()ne doit jamais être appelée à partir du thread de distribution des événements, car elle générerait une exception . La méthode SwingUtilities.isEventDispatchThread()ou EventQueue.isDispatchThread()peut être appelée pour déterminer si le thread actuel est le thread de distribution des événements.

Le code fourni par l'intermédiaire des invokeLateret invokeAndWaità l'EDT doit être le plus rapide possible pour éviter le blocage. Ils sont normalement destinés à délivrer le résultat d'un long calcul à l'interface graphique (utilisateur).

Modèle de conception de travailleur

L'exécution d'une tâche dans un autre thread et la présentation des résultats dans l'EDT peuvent être combinées au moyen du modèle de conception worker . La javax.swing.SwingWorkerclasse, développée par Sun Microsystems , est une implémentation du modèle de conception worker et, à partir de Java 6, fait partie de la distribution Swing standard. SwingWorker est normalement invoqué à partir de l'écouteur d'événements exécuté par EDT pour effectuer une tâche longue afin de ne pas bloquer l'EDT.

Échantillons

SwingWorker < Document , Void > worker = new SwingWorker < Document , Void > () { public Document doInBackground () throws IOException { return loadXML (); // tâche lourde } public void done () { try { Document doc = get (); display ( doc ); } catch ( Exception ex ) { ex . printStackTrace (); } } }; worker . execute ();

Si vous utilisez Groovy et groovy.swing.SwingBuilder, vous pouvez utiliser doLater(), doOutside(), et edt(). Vous pouvez alors l'écrire plus simplement comme ceci :

doOutside { def doc = loadXML () // tâche lourde edt { display ( doc ) } }

Equivalents

Exécution modale

SwingWorker est normalement créé pour des tâches longues par EDT lors de la gestion des événements de rappel (Listener). En générant un thread de travail, EDT continue de gérer le message en cours sans attendre que le travailleur termine. Souvent, cela n'est pas souhaitable.

Souvent, votre EDT gère une action de composant d'interface utilisateur graphique, qui demande à l'utilisateur de faire un choix au moyen d'une autre boîte de dialogue, comme JFileChooser, qui apparaît, reste réactive pendant que l'utilisateur choisit son option et l'action se poursuit avec le fichier sélectionné uniquement après avoir appuyé sur le bouton "OK". Vous voyez, cela prend du temps (l'utilisateur répond en quelques secondes) et vous avez besoin d'une interface utilisateur graphique réactive (les messages sont toujours pompés dans EDT) pendant tout ce temps pendant lequel EDT bloque (il ne gère pas les messages plus récents, par exemple JFileChooser, dans la file d'attente avant que la boîte de dialogue ne soit fermée et que l'action du composant en cours ne soit terminée). Le cercle vicieux est rompu par l'entrée d'EDT dans une nouvelle boucle de messages, qui envoie les messages normalement jusqu'à ce que "la boîte de dialogue modale est terminée" arrive et que le traitement normal des messages reprenne à partir de la position bloquée dans l'action du composant.

Le projet open source Foxtrot émule le pompage de boucle de messages Swing pour fournir le mécanisme d'exécution « synchrone » pour les tâches utilisateur arbitraires, qui ne se déroule qu'une fois que le travailleur a terminé la tâche.

bouton . addActionListener ( new ActionListener () { public void actionPerformed ( ActionEvent e ) { bouton . setText ( "En train de dormir..." );
Chaîne texte = null ; essayer { texte = ( Chaîne ) Worker . post ( nouvelle tâche () { public Object run () lève une exception { Thread . sleep ( 10000 ); renvoyer "Dormi !" ; } }); } catch ( Exception x ) ...
bouton . setText ( texte );
autrechose (); 
} });

Depuis Java 1.7, Java fournit une solution standard pour les boucles de messages secondaires personnalisées en exposant createSecondaryLoop () dans le système EventQueue ().

Plus d articles de Worldlex Wiki

Revenez a l index pour explorer davantage de pages sur l histoire, la science, la culture, la geographie et la societe en francais.

Explorer l index