J'ai un cas d'utilisation provenant d'un problème d'interface graphique que je voudrais soumettre à votre sagacité.
cas d'utilisation strong> p> J'ai une interface graphique qui affiche un résultat de calcul en fonction de certains paramètres de l'utilisateur dans une interface graphique. Par exemple, lorsque l'utilisateur déplace un curseur, plusieurs événements sont tirés, qui déclenchent tous un nouveau calcul. Lorsque l'utilisateur ajuste la valeur du curseur de A à B, une dizaine d'événements sont tirés. P> mais le calcul peut prendre jusqu'à plusieurs secondes, alors que le réglage du curseur peut déclencher un événement tous les uns de 100 ms. < / P> Comment écrire un thread approprié qui écoute ces événements et les filtreraient de manière à ce que la repeinte des résultats soit vif? Idéalement, vous voudriez quelque chose comme p> ce que j'ai essayé fort> p> Un de mes amis (A. Cardona) a proposé cette approche de faible niveau d'un thread de mise à jour qui empêche trop d'événements de déclencher un calcul. Je copier-la coller ici (gpl): p> Il la met dans une classe qui étend le thread: p> chaque fois qu'un événement est envoyé par L'interface graphique indiquant que les paramètres ont été modifiés, nous appelons Je me demandais s'il y avait une autre façon de le faire, cela utiliserait la JACA. classes simultanées. Mais je ne pouvais pas trier dans le cadre des exécutants ce qui serait celui que je devrais commencer. P> Est-ce que l'une d'entre vous a une expérience avec un cas d'utilisation similaire? p> merci p> p>
updater.doupdate () code>. Cela provoque la méthode
Actualiser () Code> à être appelée beaucoup moins.
Mais je n'ai aucun contrôle sur ceci. P>
5 Réponses :
Je fournirais un nouveau degré de déconnexion entre l'interface graphique et les commandes en utilisant une file d'attente. P>
Si vous utilisez un Votre composant graphique peut lire la file d'attente chaque fois qu'il aime et agir sur les événements arrivants ou les jeter si nécessaire. P> blockingQueue code> entre les deux processus. Chaque fois que les commandes changent, vous pouvez publier les nouveaux paramètres sur la file d'attente. P>
Je regarderais dans SwingWorker.Publish () ( http://docs.oracle.com/javase/6/docs/api/javax/swing/swingworker.html ) P>
Publier permet au fil d'antécédents d'un objet SwingWorker de causer des appels à la méthode de processus (), mais tous les appels de publication () n'appellent pas dans un processus de processus (). Si plusieurs appels de processus sont effectués avant le processus de processus () et peut être appelé à nouveau, SwingWorker concaténe les paramètres utilisés pour plusieurs appels publiés dans un appel à traiter. P>
J'ai eu une boîte de dialogue de progrès qui affichée des fichiers traités; Les fichiers ont été traités plus rapidement que l'interface utilisateur pourraient les suivre et je ne voulais pas que le traitement ralentit pour afficher les noms de fichiers; J'ai utilisé cela et j'ai eu le processus affichant uniquement le nom de fichier final envoyé au processus (); Tout ce que je voulais dans ce cas, c'était d'indiquer à l'utilisateur où le traitement actuel était, ils n'allaient pas lire tous les noms de fichiers de toute façon. Mon UI a travaillé très bien avec cela. P>
Merci! Serait-il applicable pour autre chose qu'une interface graphique?
Je ne pense pas que processus code> et
publie code> est ce que l'OP recherche. Vous ne pouvez pas mettre à jour un
swingworker code> avec de nouveaux événements. Dans ce cas, le problème est différent: le traitement est plus lent que les actions déclenchées par l'interface utilisateur.
@Andrewmao Bon point - Publier / processus met à jour une interface utilisateur dû au traitement, et ce problème inclut la mise à jour du traitement de l'interface utilisateur. Les événements générés par l'interface utilisateur sont déjà mis en file d'attente, bien sûr; Peut-être que le programme pourrait avoir reçu des événements de curseur jusqu'à ce qu'il n'y ait plus d'événements dans la file d'attente, puis commencez le traitement de la valeur la plus récente, car ceux-ci ne sont plus pertinents. Je pense donc que mon idée est pertinente pour mettre à jour l'interface utilisateur, mais vous avez raison de prendre en compte la question de l'interface utilisateur de l'interface utilisateur.
@ Jean-Yves Je ne suis pas familier avec SwingWorker pour autre chose qu'une interface utilisateur, bien que je ne sache pas que cela ne peut pas être fait. J'ai pensé à une autre façon de faire des choses: laissez le curseur lancer une minuterie; Si la minuterie est déjà en cours d'exécution, mettez à jour son délai d'attente. Lorsque la minuterie expire, commencez le traitement. De cette façon, seul le dernier dans une série d'événements de curseur en file d'attente est traité.
@ Jean-Yves regarde aussi docs.oracle.com/javase/tatuly /uiswing/components/slider.ht ml Pour plus d'informations sur l'événement de changement que vous pouvez écouter du curseur; Il présente un exemple de celui qui n'est intéressé que dans le "dernier" changement fait, c'est-à-dire non intéressé par tous les événements qui se produisent tout en faisant glisser vers une valeur finale, mais intéressé par cette valeur lorsque le glissement s'arrête.
Vérifiez la mise en œuvre de javax.swing.swingworker (code source dans le JAVA JDK),
En mettant l'accent sur la prise de main entre deux méthodes: publier em> et processus em>. p>
Ceux-ci ne seront pas directement applicables, selon votre problème, mais ils démontrent comment vous pouvez faire la queue (publication) mises à jour sur un thread de travailleur, puis les servir dans votre thread de votre travailleur (processus). P>
Comme vous n'avez besoin que de la dernière demande de travail, vous n'avez même pas besoin d'une file d'attente pour votre situation: Ne gardez que la dernière demande de travail. Échantillon que "Dernière demande" sur une petite période (1 seconde), pour éviter d'arrêter / redémarrer plusieurs fois toutes les 1 seconde, et s'il est changé, arrêtez le travail et redémarrez. P>
La raison pour laquelle vous ne voulez pas utiliser Publier em> / le processus em> est que processus em> fonctionne toujours sur le thread d'expédition Swing Event Dispatch - Pas du tout adapté aux calculs de longue course. P>
Cela dépend de la façon dont il l'utilise - si tout le processus fait la mise à jour de l'interface utilisateur, c'est exactement ce qu'il veut. Il n'a pas à (et ne devrait pas) faire son long calcul là-bas, je suis d'accord. Mais c'est parfaitement juste pour une partie de son problème.
Si vous utilisez feu un à la fois l'action et le Notez que cela fait efficacement la même chose qui permet à une interface graphique d'annuler une opération existante, sauf L'annulation est effectuée automatiquement lorsqu'une nouvelle demande est tirée. p> p> Swing code>, le
swingworker code> fournit des capacités pour cela et que vous n'avez pas à gérer la piscine de fil vous-même.
swingworker code> pour chaque demande. Si une nouvelle demande est entrée et que le travailleur n'est pas terminé, vous pouvez
Annuler () CODE> IT, et simplement démarrer un nouveau
swingworker code>. Concernant ce que l'autre affiche a dit, je ne pense pas
publier () code> et
processus () code> sont ce que vous recherchez (bien qu'ils soient aussi très utiles), puisqu'ils sont destinés à un cas où le travailleur pourrait déclencher des événements plus rapidement que l'interface graphique ne peut le traiter. p>
effectué () code> La méthode est exécutée sur le même thread, elles peuvent donc vérifier efficacement la référence pour savoir s'il existe un travailleur existant. P>
bonne solution. Mais il n'est pas clair pour moi s'il y a une petite chance qu'après travailleur1.cancel () code>,
travailleur1.done () code> est toujours exécuté, et il peut être exécuté après
travailleur2.done () code>, c'est-à-dire qu'un seul résultat écrase un résultat plus récent. besoin d'un peu plus d'investigation ici.
Cela ne résout pas le problème de la manière de lotter les demandes, d'éviter la situation où vous annulez et redémarrez le fil de plusieurs fois sur une courte période.
Je ne pense pas que vous puissiez jamais éviter d'annuler les demandes, car vous ne savez jamais si une demande est la dernière. Bien sûr, vous pouvez attendre un peu avant de tirer des travailleurs, pour voir si plus de demandes arrivent, mais cela rendrait la mise à jour plus lente.
@ zhong.j.yu Si même possible, semble très improbable que travailleur2.doinbackground () code> prendra beaucoup plus de temps que
travailleur1.cancel () code>. Aussi depuis le
Annuler () code>,
exécuter () code> et
effectué () code> sont tous dans le thread d'expédition d'événement, il semble que
annule () code> devrait empêcher
effectué () code> à partir d'être appelé si Swing se synchronise correctement. Il n'y a pas d'état de course dans l'annulation ici.
La clé ici est que vous souhaitez pouvoir annuler un calcul en cours. Le calcul doit fréquemment vérifier une condition pour voir si elle doit interrompre.
public void run() while(true) Param param = take(); Result result = compute(param); if(result!=null) paint result in event thread
Je ne sais pas «vérifier fréquemment une condition», aka scrutin; C'est ce que font les interruptions.
Comment interrompez-vous une boucle occupée :?)