Mon application possède une barre d'outils et de nombreux boutons. Certains boutons démarrent de longs processus (tâches). À ce moment, chaque tâche s'exécute de manière asynchrone pour permettre à l'utilisateur de faire autre chose pendant l'exécution de la tâche. J'ai donc un problème: l'utilisateur peut cliquer plusieurs fois sur le même bouton pour démarrer d'autres tâches identiques. J'ai décidé de désactiver le bouton avant de commencer la tâche et de l'activer après la fin. Autre problème, je devrais protéger les autres boutons de la pression (certains d'entre eux seraient désactivés après avoir effectué les tâches en cours). En général, je dois désactiver tous les boutons (barre d'outils) pour être sûr que l'utilisateur ne peut pas faire quelque chose de dangereux avec des boutons en transitoire. Mes questions sont:
Quelqu'un pourrait-il recommander un moyen de distraire les utilisateurs du scintillement (boutons désactiver/activer) ou comment les impliquer dans le processus, comment les faire remplir cette tâche n'est pas si long?
Peut-être que je devrais exécuter les tâches de manière synchrone et désactiver toutes les interfaces utilisateur pendant la durée d'exécution?
Soit dit en passant: le délai peut varier de 1 à 10 secondes. À propos de la barre de progression: il est difficile de calculer la progression actuelle et cela entraîne une dégradation des performances (la tâche peut être effectuée plus rapidement sans itérations d'interface utilisateur supplémentaires à partir d'autres threads).
En fin de compte, c'est un problème de tenir l'utilisateur informé en fournissant de bons commentaires.
La première chose à faire tout de suite est d'indiquer que le bouton a été pressé et de ne pas leur laisser penser qu'il peut être pressé à nouveau. Cela se fait souvent en désactivant le bouton, mais voir plus loin ci-dessous pour une alternative.
Étant donné que votre délai peut être de longueur variable, la méthode doit alors être en mesure d'informer l'utilisateur du temps que prendra la tâche. Si le calcul de la progression est trop difficile, vous pouvez indiquer que cela ne prendra "que quelques secondes". Assurez-vous d'utiliser une terminologie positive.
Je ne suis vraiment pas fan de désactiver temporairement des morceaux d'interface utilisateur - il y a toujours ce risque qu'il ne soit pas réactivé si quelque chose échoue. Donc, lorsque j'ai besoin de bloquer l'interface utilisateur, je préférerais l'option d'une boîte de dialogue modale pour informer l'utilisateur du message ci-dessus. En outre, la désactivation de l'interface utilisateur n'est pas un mécanisme de rétroaction directement lié, c'est un hack de programmation et laisse simplement l'utilisateur se demander ce qui se passe.
Donc, pour donner à l'utilisateur des commentaires sur la tâche en cours, utilisez une boîte de dialogue modale pour afficher le message ci-dessus et bloquer l'application, ou affichez-le dans une zone de rétroaction/état dans l'application, selon que vous souhaitez que l'utilisateur soit incapable/capable d'interagir avec l'interface utilisateur.
Si vous décidez d'autoriser les utilisateurs à accéder au reste de l'interface utilisateur, alors que la tâche est active, toutes les fonctionnalités devraient sembler fonctionner normalement. Sur le bouton qui a démarré la tâche active, vous pouvez indiquer que cette fonction particulière est active. Généralement, cela se fait en désactivant le bouton, mais une idée plus directement communicative consiste à ajouter une icône d'angle au bouton pour indiquer l'état actif. Cela pourrait être un petit sablier ou une autre icône occupée. Si l'utilisateur clique sur le bouton, il peut simplement être informé que l'action est déjà active. Les info-bulles peuvent également indiquer l'état actif. Cette idée de rétroaction contextuelle par bouton très localisée devrait fonctionner très bien.
Idéalement, vous voudriez que votre application soit aussi réactive que possible aux entrées des utilisateurs. Il est donc tout à fait logique d'effectuer des tâches de longue durée de manière asynchrone.
Dans la mesure où l'utilisateur soumet à nouveau la même tâche, vous avez quelques options:
Désactiver le bouton avant la tâche/activer après la tâche (ce serait mon choix par défaut sans savoir exactement ce que fait votre application): Il semble que vous l'ayez déjà fait. Développer la logique correcte pour désactiver/activer les boutons peut devenir complexe mais en vaut la peine si cela rend votre application plus intuitive pour l'utilisateur final.
Mettre en cache les tâches soumises: si un utilisateur soumet une tâche, mettre en cache les paramètres d'entrée. Lorsqu'il soumet la tâche une deuxième fois et que les paramètres d'entrée sont dans le cache, ne démarrez pas la tâche une seconde fois (car elle est déjà en cours d'exécution). Cette option dépend de l'exécution de la tâche étant idempotente, elle ne s'applique donc pas à tous les cas, mais lorsque vous pouvez utiliser, vous n'avez pas à vous soucier de la désactiver/logique d'activation.
Il suffit d'exécuter la tâche plusieurs fois: ceci n'est pas recommandé (!) comme approche, bien que dans certains cas cela puisse faire sens. Par exemple, si vous construisez uniquement un prototype (comme un produit peu viable), vous souhaitez diffuser l'application dès que possible. Dans ce cas, il est plus important d'apprendre à utiliser l'application que de gaspiller des ressources informatiques. Il se peut que ces tâches ne soient même pas utilisées, vous gagneriez donc du temps en ne développant rien pour elles.
Si vous voulez éviter le scintillement, vous pouvez suivre les conseils de Joel: "Ne pas masquer ou désactiver les éléments de menu" et lorsqu'un utilisateur appuie sur un bouton de la barre d'outils pour quelque chose qui est déjà en cours d'exécution ou qui interférerait avec une autre exécution tâche, vous pouvez ensuite afficher un message expliquant pourquoi vous ne pouvez pas terminer la demande des utilisateurs ou "mettre en cache les tâches soumises" (et avoir une fenêtre de tâches à exécuter) ou simplement faire ce que l'utilisateur demande et l'exécuter à nouveau (soyez conscient des problèmes de synchronisation ici).
Une suggestion rapide: pouvez-vous en faire un "bouton de case à cocher", son état "Pressé"/"Vérifié" indique que la tâche est en cours d'exécution. Puis "décompressez"/"décochez" automatiquement lorsque la tâche asynchrone se termine?
Je ne désactiverais pas le bouton, mais au lieu de cela, je m'assurerais que l'action est appelée alors qu'elle était déjà en cours d'exécution. Je voudrais cependant m'assurer qu'il y a une bonne rétroaction lorsque l'action est en cours d'exécution et lorsqu'elle est terminée.