2 votes

Dans Delphi 2010, l'événement Click est traité alors que le bouton correspondant est désactivé.

Considérons le morceau de code suivant exécuté dans l'événement OnClick d'un bouton donné :

procedure TForm1.Button1Click(Sender: TObject);
begin
  button1.enabled := false;    //Line 1  
  application.processmessages; //Line 2  
  Sleep(3000);                 //Line 3
  button1.enabled := True;     //Line 4
  Release;                     //Line 5
end;

Dans Delphi 2010, si après avoir cliqué sur ce bouton, vous parvenez à effectuer un autre un autre clic pendant que l'exécution est en cours à la ligne 3, l'événement de sera apparemment stocké dans la file d'attente des commandes, ainsi, lorsque la procédure Release(Ligne 5) est appelée, l'application tentera de le traiter. l'application tentera de le traiter. Par conséquent, l'événement de clic sera déclenché une fois de plus. La deuxième fois le composant bouton a déjà été détruit, donc l'erreur de "violation d'accès" est levée.

L'ensemble du concept de reconnaissance du second clic par le système lorsque le respectif est désactivé, ne semble pas judicieux. Une explication à ce comportement douteux ?

4voto

David Heffernan Points 292687

Le système se comporte exactement comme prévu, mais sachez que votre code va à l'encontre de tous les principes de conception. Plus précisément, l'utilisation de Sleep y ProcessMessages dans un gestionnaire d'événement d'entrée sont toutes deux à désapprouver.

La raison pour laquelle le programme se comporte de cette manière est la suivante :

  1. L'utilisateur génère un message d'entrée en cliquant sur la souris.
  2. Cet événement d'entrée est placé dans la file d'attente d'entrée du thread approprié.
  3. Ce thread ne sert pas sa file d'attente d'entrée (il dort) et donc le message d'entrée, qui est une combinaison de souris vers le bas et de souris vers le haut, reste là.
  4. Le fil se réveille et active le bouton.
  5. Le bouton OnClick revient et la boucle de messages de l'application continue.
  6. En temps voulu, les messages de la souris vers le bas et de la souris vers le haut sont traités (avant que l'option CM_RELEASE ) et donc le bouton OnClick Le gestionnaire s'exécute à nouveau.
  7. Le bouton OnClick appels du gestionnaire ProcessMessages qui gère ensuite le CM_RELEASE et tue le formulaire.
  8. BOOM !

Le concept de reconnaissance du second clic par le système lorsque le bouton correspondant est désactivé ne semble pas judicieux.

Le point clé est que l'état activé du bouton est vérifié quand le message d'entrée est traité et non lorsque le message d'entrée est généré . Il doit en être ainsi car les messages d'entrée sont des éléments de très bas niveau, et seule l'application peut les interpréter comme des clics de bouton.

Il existe de nombreuses façons de corriger votre code, mais je ne suis pas disposé à en suggérer car il s'agit clairement d'un code d'illustration. Mais je dirai que toutes les bonnes solutions impliquent la suppression des appels à Sleep et `ProcessMessages.

0voto

GolezTrol Points 54531

Pendant le sommeil, votre application n'est pas réactive. Le message de clic est mis en file d'attente et n'est traité qu'après la réactivation du bouton (en fait, après l'exécution complète de la méthode de gestion de l'événement et après que l'application soit redevenue inactive).

Pour résoudre ce problème, exécutez également Application.ProcessMessages après le sommeil, avant d'activer le bouton. Cela videra d'abord votre file d'attente de messages et rejettera le message de clic.

Ou alors, n'activez pas le bouton du tout. Pourquoi le feriez-vous, si vous allez libérer le formulaire de toute façon ?

Une solution (probablement) meilleure serait d'exécuter le Sleep dans un thread séparé, mais comme Sleep ici n'est probablement qu'un stub pour du vrai code, il est difficile de dire quel effort cela demandera.

Quoi qu'il en soit, votre application actuelle n'est pas bonne, et l'appel à Application.ProcessMessages dans des situations comme celle-ci est susceptible de générer des bogues "aléatoires" de temps à autre. Le mieux que vous puissiez faire est de limiter le risque, mais il n'y a pas de bon moyen de le résoudre, sauf à changer radicalement cette implémentation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X