Nous avons vu que la structure de l'interface utilisateur JFace permet la prise en charge standard de l'affichage de la progression des tâches dans une boîte de dialogue (pour plus d'informations, reportez-vous à la section Opérations longues). Dans la section Infrastructure d'accès concurrent, nous avons étudié la prise en charge de l'exécution de la plate-forme pour l'accès concurrent et les opérations longues. A présent, nous allons observer comment l'interface utilisateur de la plate-forme améliore cette infrastructure dans le package
org.eclipse.ui.progress. Ce package met à disposition l'interface utilisateur pour afficher la progression des tâches dans le plan de travail et définit la prise en charge complémentaire pour les tâches qui s'exécutent sur l'unité d'exécution de l'interface utilisateur.
Regardons d'abord les différentes opérations d'arrière-plan en cours de fonctionnement et comment elles s'affichent sur l'interface utilisateur du plan de travail :
User initiated Opérations déclenchées par l'utilisateur. Le plan de travail affiche automatiquement les tâches utilisateur dans une boîte de dialogue modale indiquant la progression et comprenant un bouton pour permettre à l'utilisateur d'exécuter l'opération en tâche de fond et de continuer à travailler. Une préférence globale est utilisée pour indiquer si les tâches utilisateur doivent toujours s'exécuter en arrière-plan. Les tâches utilisateur sont qualifiées comme telles par l'utilisation du processus API (Job#setUser). Elles comprennent notamment la génération et l'extraction d'un projet, la synchronisation avec le référentiel, l'exportation d'un plug-in et la recherche.
Automatically triggered Les opérations sont comprises par l'utilisateur bien qu'il ne les ait pas initiées. Ces tâches sont indiquées dans la vue de progression et dans la ligne d'état, mais aucune boîte de dialogue modale de progression ne s'affichera lors de leur exécution. La création automatique et la synchronisation planifiée en sont des exemples.
System operations Ces opérations ne sont pas initiées par l'utilisateur et peuvent être considérées comme un élément d'implémentation de plateforme. Ces tâches sont créées en définissant l'indicateur système à l'aide de (Job#setSystem). Les tâches qui peuplent lentement les widgets ou calculent les décorations et les annotations des vues en sont des exemples.
Dans un environnement où plusieurs événements peuvent se produire en même temps, un utilisateur a besoin des éléments suivants :
Indication informant qu'une opération longue a commencé.
Les tâches utilisateur sont affichées à l'attention de l'utilisateur dans une boîte de dialogue de progression indiquant un retour immédiat, tandis que les tâches déclenchées automatiquement sont affichées dans la ligne d'état et dans la vue de progression. Les tâches qui affectent un composant doivent être planifiées ou enregistrées avec le composant afin que le plan de travail puisse signaler à l'utilisateur qu'une opération est en cours d'exécution et qu'elle a un impact sur le composant.
Indication informant qu'une opération est terminée.
L'utilisateur peut facilement savoir quand une tâche utilisateur est terminée car la boîte de dialogue de progression se ferme. Pour les tâches non-utilisateur, il existe quelques mécanismes de retour. Si la tâche est planifiée ou enregistrée avec un composant, l'indication de progression des composants s'affichera à la fin. Si une tâche renvoie une erreur, un indicateur d'erreur s'affiche dans la partie inférieure droite de la ligne d'état et signale qu'une erreur s'est produite.
Indication concernant les nouveaux résultats intéressants ou les nouvelles informations, sans toutefois affecter la tâche principale par l'utilisation d'une boîte de dialogue.
Une tâche utilisateur peut afficher directement les résultats à l'attention de l'utilisateur lorsque l'opération est terminée. Pour les tâches non-utilisateur, il est recommandé d'utiliser un autre mode d'affichage que la boîte de dialogue afin de ne pas interrompre l'utilisateur. Par exemple, il est possible d'ouvrir une vue au démarrage de la tâche et d'y afficher les résultats sans interrompre le flux de travaux de l'utilisateur. Par ailleurs, vous pouvez ajouter des Propriétés de la tâche à la tâche pour indiquer qu'elle doit être conservée dans la vue de progression et qu'elle engendrera une action d'affichage des résultats. Dans ce cas, un message d'avertissement apparaîtra dans le coin inférieur gauche de la ligne d'état lorsqu'une tâche se trouve dans la vue et a des résultats à montrer à l'utilisateur.
Un sentiment général de contrôle de ce qui est exécuté avec la possibilité de surveiller et d'annuler les opérations en tâche de fond.
Les tâches utilisateur offrent le meilleur contrôle à l'utilisateur car elles sont faciles à annuler et affichent des indications évidentes de blocages ou d'opérations exécutées simultanément via l'onglet Détails de la boîte de dialogue de progression. Notez que la boîte de dialogue de progression améliorée qui affiche la zone Détails n'est affichée que lorsque les plug-ins utilisent IProgressService#busyCursorWhile
ou IProgressService#runInUI.
En outre, la vue de progression permet d'accéder aux tâches qui sont en cours d'exécution.
Signalement de la progression par tous les plug-ins installées.
L'avantage d'utiliser l'API de service de progression est que les utilisateurs bénéficient d'une progression cohérente.
Le service de progression du plan de travail (IProgressService) est l'interface principale pour la prise en charge de la progression dans le plan de travail. Ce service est disponible à partir du plan de travail et est utilisé pour afficher la progression pour les opérations en tâche de fond et les opérations qui sont exécutées au niveau de l'unité d'exécution de l'interface utilisateur. L'objectif principal de cette classe est de proposer un point unique pour exécuter des opérations, supprimer la nécessité, pour les développeurs de plug-ins, de déterminer le plug-in à utiliser pour afficher la progression dans une situation donnée. Un autre avantage est que la boîte de dialogue de progression affichée avec ces méthodes permet une prise en charge appropriée pour indiquer le blocage d'une opération par une autre opération et donner à l'utilisateur le moyen de contrôler la résolution du conflit. Lorsque cela est possible, les opérations longues doivent être exécutées à l'aide de IProgressService#busyCursorWhile:
IProgressService progressService = PlatformUI.getWorkbench().getProgressService(); progressService.busyCursorWhile(new IRunnableWithProgress(){ public void run(IProgressMonitor monitor) { // Pour effectuer un travail qui n'est pas associé à l'interface utilisateur } });
Cette méthode utilise à l'origine un curseur indiquant l'état d'occupation et le remplace par une boîte de dialogue de progression si l'opération dure au-delà d'une durée seuil spécifiée. L'avantage de cette méthode par rapport à une boîte de dialogue de progression est que si l'opération est courte, la boîte de dialogue ne s'affiche pas. Si votre opération doit mettre à jour l'interface utilisateur, vous pouvez toujours utiliser Display.asyncExec ou Display.syncExec pour exécuter le code qui modifie l'interface utilisateur.
Si une opération doit être exécutée dans son intégralité dans l'unité d'exécution de l'interface utilisateur, alors vous devez utiliser IProgressService#runInUI. L'avantage de cette méthode est qu'elle affiche une boîte de dialogue de progression si l'opération est bloquée tout en donnant le contrôle à l'utilisateur.
progressService.runInUI( PlatformUI.getWorkbench().getProgressService(), new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { // Pour effectuer un travail associé à l'interface utilisateur } }, Platform.getWorkspace().getRoot());
Le troisième paramètre peut prendre la valeur null ou il peut s'agir d'une règle de planification pour l'opération. En pareil cas, nous spécifions la racine du plan de travail qui va, pour l'essentiel, verrouiller l'espace de travail lorsque l'opération de l'interface utilisateur est exécutée.
Vous pouvez également enregistrer une icône d'une famille de tâches dans le service de progression afin que la vue de progression puisse afficher l'icône en regard de la tâche en cours d'exécution. Voici un exemple qui montre comment une famille de tâches créée automatiquement est associée à une icône :
IProgressService service = PlatformUI.getWorkbench().getProgressService(); ImageDescriptor newImage = IDEInternalWorkbenchImages.getImageDescriptor( IDEInternalWorkbenchImages.IMG_ETOOL_BUILD_EXEC); service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_MANUAL_BUILD); service.registerIconForFamily(newImage, ResourcesPlugin.FAMILY_AUTO_BUILD);
IWorkbenchSiteProgressService comprend une API pour la planification des tâches qui modifient l'apparence d'un composant du plan de travail lors de l'exécution de la tâche. Si votre plug-in exécute des opérations d'arrière plan qui affectent l'état d'un composant, vous pouvez planifier la tâche via le composant. Ainsi l'utilisateur est averti par un retour que le composant est occupé. Voici un exemple :
IWorkbenchSiteProgressService siteService = (IWorkbenchSiteProgressService)view.getSite().getAdapter(IWorkbenchSiteProgressService.class); siteService.schedule(job, 0 /* now */, true /* use the half-busy cursor in the part */);
Le plan de travail définit les propriétés liées à la progression des tâches dans IProgressConstants . Celles-ci peuvent être utilisées pour contrôler l'affichage d'une tâche dans la vue de progression. Ces propriétés peuvent également être utilisées pour indiquer à la vue de progression de conserver (IProgressConstants#KEEP_PROPERTY) la tâche dans la vue une fois qu'elle est terminée, ou de ne conserver (IProgressConstants#KEEPONE_PROPERTY) qu'une tâche à la fois dans la vue. Vous pouvez également associer une action (IProgressConstants#ACTION_PROPERTY) à une tâche. Lorsqu'une tâche possède une action associée, la vue de progression affiche un lien hypertexte afin que l'utilisateur puisse exécuter l'action. Vous pouvez également savoir si une tâche utilisateur est actuellement affichée dans une boîte de dialogue de progression (IProgressConstants#PROPERTY_IN_DIALOG). Une indication dans la partie inférieure droite de la ligne d'état signale lorsqu'une action est disponible. L'exemple suivant utilise ces propriétés :
Job job = new Job("Do Work") { public IStatus run(IProgressMonitor monitor) { // do some work. // Keep the finished job in the progress view only if it is not running in the progress dialog Boolean inDialog = (Boolean)getProperty(IProgressConstants.PROPERTY_IN_DIALOG); if(!inDialog.booleanValue()) setProperty(IProgressConstants.KEEP_PROPERTY, Boolean.TRUE); } }; job.setProperty(IProgressConstants.ICON_PROPERTY, Plugin.getImageDescriptor(WORK_IMAGE)); IAction gotoAction = new Action("Results") { public void run() { // Pour afficher les résultats } }; job.setProperty(IProgressConstants.ACTION_PROPERTY, gotoAction); job.setUser(true); job.schedule();
Lorsque cela est possible, les opérations longues doivent être réalisées en dehors de l'unité d'exécution de l'interface utilisateur. Cependant, il n'est pas toujours possible d'éviter cet état de fait lorsque l'objectif de l'opération est de mettre à jour l'interface utilisateur. La section Problèmes liés aux unités d'exécution SWT explique comment cette opération peut être réalisée à l'aide de l'affichage SWT. Le plan de travail définit une tâche spéciale, UIJob, dont la méthode run est exécutée dans un élément asyncExec SWT. Les sous-classes de UIJob doivent implémenter la méthode runInUIThread au lieu de la méthode run.
WorkbenchJob étend UIJob afin que la tâche ne puisse être planifiée ou exécutée que lorsque le plan de travail est en cours d'exécution. Comme toujours, vous devez éviter le travail en excès au niveau de l'unité d'exécution de l'interface utilisateur car celle-ci n'est pas actualisée pendant la durée de la tâche de l'interface utilisateur.