Evènement OnMouseMove inapproprié [Résolu]

Signaler
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
-
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
-
Salut à tous !

Je rencontre un problème assez étrange: j'implémente les évènements OnMouseDown et OnMouseMove de ma fiche et lorsque je sélectionne un fichier par double-clic dans un TOpenDialog, la fiche reçoit un évènement OnMouseMove indiquant que le bouton gauche est enfoncé.

Or, aucun évènement OnMouseDown n'a été généré auparavant !

C'est assez problématique car je fais des initialisations dans le OnMouseDown, partant du principe que celui-ci est forcément appelé avant que le OnMouseMove ne soit appelé avec "ssLeft in Shift".
Et ça fait de la corruption de données !

Je voudrais donc savoir si j'ai loupé un truc ou si c'est vraiment un bug de Delphi, auquel cas ça risque d'être assez ennuyant.

NB: notez bien que le problème ne se passe que lors d'un double-clic sur un fichier dans le TOpenDialog, pas si on clique sur "ouvrir".

Merci de bien vouloir m'éclairer,
Flo

12 réponses


Salut,

Flo désolé mais j'ai rien compris à ta question . J'ai essayé de reproduire ton probleme et aucun evenement OnMouse n'est déclenché quand je sélectionne un fichier via un TOpenDialog
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
Purée, alors, je viens de refaire le test juste avec un TForm et un TOpenDialog et j'ai bien ce problème.
Il faut bien sûr que le TOpenDialog soit au dessus du TForm.

Le problème:
J'ai un évènement OnMouseMove qui se déclenche avec comme paramètre Shift = [ssLeft] alors qu'aucun évènement MouseDown ne m'a prévenu que le bouton gauche a été enfoncé.
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
Voila juste ce qui suffit à faire planter : on obtient le message 'MouseMove avec bouton gauche enfoncé' mais pas l'autre ! snif !

(NB: il faut sélectionner un fichier par double-clic dans le TOpenDialog)



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
{ Juste pour être sur que le TOpenDialog sera au dessus de la fiche }
SetBounds(0, 0, Screen.Width, Screen.Height);

OpenDialog1.Execute;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then ShowMessage('Clic gauche');
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if ssLeft in Shift then ShowMessage('MouseMove avec bouton gauche enfoncé');
end;

end.
Messages postés
3825
Date d'inscription
vendredi 23 juillet 2004
Statut
Modérateur
Dernière intervention
1 février 2021
40
Salut,

je viens de tester la chose et j'obtiens le même résultat que toi sous Turbo Delphi ...

à mon avis c'est un Bug de Delphi ...
il faudrait peut être remonter l'info

 
@+
Cirec

<hr siz="" />
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
Bon Ok, c'est donc pas une bourde que j'ai fait !!!

Voila donc tout ce que j'ai pu trouver pour pallier au problème (c'est pas super propre mais on fait comme on peut):

- déclarer un membre FLastShiftState: TShiftState dans la section private

- surcharger MouseDown et MouseMove par ça :

1. Pour MouseMove:

if (ssLeft in Shift) and not (ssLeft in FLastShiftState) then
MouseDown(mbLeft, FLastShiftState + [ssLeft], X, Y);
if (ssRight in Shift) and not (ssRight in FLastShiftState) then
MouseDown(mbLeft, FLastShiftState + [ssRight], X, Y);
if (ssMiddle in Shift) and not (ssMiddle in FLastShiftState) then
MouseDown(mbLeft, FLastShiftState + [ssMiddle], X, Y);
inherited;

2. Pour MouseDown:

FLastShiftState := Shift;
inherited;

Voila. C'étaient mes 2cts de bug de Delphi !
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
Zuuut ! c'est mbLeft, mbRight et mbMiddle et non pas mbLeft tout le temps !!!

D'ailleurs, comme on ne peut que double-cliquer avec le bouton gauche (il me semble) le problème ne devrait pas arriver avec les autres boutons, non ?
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
C'est encore moi !

Je viens de faire quelques autres tests, et aparament, le problème ne survient qu'avec les dialogues de Delphi.
Si on ferme une fiche en lui mettant Close dans le OnDblClick, la fiche d'en dessous ne reçoit aucun MouseMove, ni MouseDown, ce qui est l'effet normal.

Finalement, au lieu de recréer des évènements MouseDown, on ferait peut être mieux de supprimer les MouseMove qui n'ont rien à faire là.

Bon j'ai aussi l'erreur : l'evenement OnMouse est déclenché.
Messages postés
4297
Date d'inscription
samedi 19 janvier 2002
Statut
Modérateur
Dernière intervention
9 janvier 2013
31
Je confirme et j'avoue que ça me laisse perplexe...

May Delphi be with you !
<hr color="#008000" />Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.
Messages postés
4202
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
13 juin 2020
37
Logique :

Quand tu es sur ta fiche (focused) elle recois les evenement MouseUp/Down  ... normal

Quand ta fiche PERD le focus elle perd egalement les evements MouseUp/Down ... normal

MAIS

Quand la fiche reprend le focus, alors qu'un doubleclick souris est en cours, la fiche receptionne le MouseUp ... puisque pendant le doubleclick sur un dialog (opendialog) voici ce qui se passe :

click bouton ouvrir = Affiche OpenDialog > click down ouvrir > click up ouvrir > click ok > Cache Opendialog > retour a la fiche principale.

doubleclik sur un fichier = Affiche OpenDialog > click down fichier > click up fichier > click down fichier > double click ok > ferme opendialog > retour a la fiche principal > click up anormal.

en fait cela viens du fait que le double click est validé dés le deuxieme down de curseur et non aprés le deuxieme up.
donc le deuxieme up intervient n'importe ou ... en gros il est perdus.
c'est plus un bug windows qu'un bug delphi.

le mieux serait de forcer l'ordre d'execution des 3 procedures :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Button1Click(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormCreate(Sender: TObject);
  private
    FDmu : byte;
  protected
    function SafeDMUOrder(const Order: byte): boolean;
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FDMU := 0;
end;

function TForm1.SafeDMUOrder(const Order: byte): boolean;
begin  Result :FDMU Order;
  if Result then
    FDMU := (FDMU+1) mod 3
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if SafeDMUOrder(0) then
    ListBox1.Items.Add('down');
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if SafeDMUOrder(1) then
    ListBox1.Items.Add('move');
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if SafeDMUOrder(2) then
    ListBox1.Items.Add('up');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  OpenDialog1.Execute;
end;

end.
 


Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
Tu mets le doigt dessus cher f0xi !

Mais tu oublies un détail dans ton test: les paramètres Button et Shift !!
Avec ta méthode, je me retrouve quand même avec un MouseMove et Shift = [ssLeft].

Donc, en m'inspirant de ton idée d'inhibiteur, j'ai rajouté le test des états des boutons, et voila ce que ça donne:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

const
CMouseDownLeft = 1;
CMouseUpLeft = 2;
CMouseMoveLeft = 4;

type
TForm1 = class(TForm)
Button1: TButton;
OpenDialog1: TOpenDialog;
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Button1Click(Sender: TObject);
private
// Les prochains évènements qu'on accepte
FAllowedMouseEvent: Byte;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

function ButtonToStr(Button: TMouseButton): string;
begin
case Button of
mbLeft: Result := 'mbLeft';
mbRight: Result := 'mbRight';
mbMiddle: Result := 'mbMiddle';
end;
end;

function ShiftToStr(Shift: TShiftState): string;
begin
Result := '[ ';
if ssLeft in Shift then Result := Result + 'ssLeft ';
if ssRight in Shift then Result := Result + 'ssRight ';
if ssMiddle in Shift then Result := Result + 'ssMiddle ';
Result := Result + ']';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FAllowedMouseEvent := CMouseDownLeft;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if (Button mbLeft) and (FAllowedMouseEvent and CMouseDownLeft 0) then
Exit;
FAllowedMouseEvent := CMouseUpLeft or CMouseMoveLeft;

ListBox1.Items.Insert(0, 'Down - Button = ' + ButtonToStr(Button)
+ ' - Shift = ' + ShiftToStr(Shift));
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if (Button mbLeft) and (FAllowedMouseEvent and CMouseUpLeft 0) then
Exit;
FAllowedMouseEvent := CMouseDownLeft;

ListBox1.Items.Insert(0, 'Up - Button = ' + ButtonToStr(Button)
+ ' - Shift = ' + ShiftToStr(Shift));
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if (ssLeft in Shift) and (FAllowedMouseEvent and CMouseMoveLeft = 0) then
Exit;
// ne change pas les évents acceptés

ListBox1.Items.Insert(0, 'Move - Shift = ' + ShiftToStr(Shift));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
OpenDialog1.Execute;
end;

end.



C'est déjà plus compliqué !
Et il reste un mini bug (mais faut vraiment y aller pour y arriver):
- ouvrir le opendialog
- enfoncer le bouton du milieu (et le laisser enfoncé)
- double-cliquer sur un fichier pour l'ouvrir (tout en gardant le bouton du milieu enfoncé)
- bouger la souris dans la form.

On obtient ainsi un "Move - Shift [ ssMiddle ]" puis un "Up - Button [ mbMiddle ]" sans avoir eu l'évènement Down correspondant (ce qui est logique, il a eu lieu ailleurs !)
Messages postés
1023
Date d'inscription
dimanche 1 août 2004
Statut
Membre
Dernière intervention
17 août 2008
2
De la même façon, si on appuie dans la fiche sur un bouton, et qu'on relache ailleurs de la fiche, elle ne reçoit pas le MouseUp.

C'est plutôt pas pratique !!!