2010-07-19 3 views
2

J'ai un comportement étrange avec TStringGrid dans Delphi 7. Delphi n'appelle pas l'événement OnMouseUp si un menu contextuel est associé à la grille. Fondamentalement, lorsque le bouton RMB est pressé, la pop du menu annule/retarde l'OnMouseUp. En fait, pour être précis à 100%, la prochaine fois que vous appuierez sur un bouton de la souris, OnMouseUp est appelé deux fois - une fois pour l'événement en cours, et une fois pour l'événement perdu/retardé. Cela va vider toute la logique du programme car le code indésirable sera appelé la prochaine fois que l'utilisateur appuie sur un bouton de la souris.TStringGrid - OnMouseUp n'est pas appelé!

Répondre

0

je l'ai déjà pris une approche en quelque sorte similaire à celle décrite par Sertac: Je ne l'utilise plus la propriété PopupMenu pour attribuer un menu contextuel au réseau. Au lieu de cela, à l'intérieur de ma grille (ma grille est une grille de chaînes fortement modifiée dérivée de TStringGrid) je gère l'événement souris et affiche le pop-up comme je veux ET fais le traitement supplémentaire que je voulais faire AVANT le menu apparaît.

4

L'ouverture automatique d'un menu contextuel est une réponse à un clic droit de la souris. Le même clic déclenche également l'événement OnMouseUp. Les développeurs VCL peuvent soit choisir de déclencher l'événement 'OnMouseUp' avant que le popup soit affiché, soit après. Apparemment, ce dernier est en effet, c'est-à-dire que l'événement est déclenché lorsque le popup est fermé (soit par la souris ou par le clavier comme si vous pressiez 'Esc').

Il n'y a pas de doublage de l'événement, lorsque vous appuyez sur le bouton gauche pour fermer la fenêtre contextuelle, vous déclenchez à nouveau l'événement 'OnMouseUp' en relâchant le bouton gauche.


Vous avez plusieurs alternatives. L'une consiste à dériver une nouvelle classe et à remplacer la méthode MouseDown pour déclencher votre propre événement. Un exemple;

type 
    TMyStringGrid = class(TStringGrid) 
    private 
    FOnRButtonUp: TMouseEvent; 
    protected 
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; 
     X, Y: Integer); override; 
    published 
    property OnRButtonUp: TMouseEvent read FOnRButtonUp write FOnRButtonUp; 
    end; 
[...] 

procedure TStringGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, 
    Y: Integer); 
begin 
    if (Button = mbRight) and Assigned(FOnRButtonUp) then 
    FOnRButtonUp(Self, Button, Shift, X, Y); 
    inherited; 
end; 


Une autre alternative peut être à gérer un message VM_RBUTTONUP. Cela peut être fait en dérivant une nouvelle classe comme ci-dessus, ou en remplaçant le WindowProc de la grille. Il y a un exemple de remplacement du WindowProc here dans ce question. Une autre alternative peut être de laisser l'événement de souris seul et de faire votre traitement dans l'événement OnPopup du menu contextuel. Cet événement est déclenché avant que la fenêtre contextuelle ne s'affiche. Vous pouvez obtenir les coordonnées de la souris avec Mouse.CursorPos.


Pourtant, une autre alternative peut être de définir la propriété AutoPopup du menu contextuel à False, et en cas OnMouseUp (ou mieux encore en cas OnContextMenu) d'abord faire un peu de traitement et de montrer ensuite le menu contextuel. Un exemple;

procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    Pt: TPoint; 
begin 
    // Do processing 

    if Button = mbRight then begin 
    Pt := (Sender as TStringGrid).ClientToScreen(Point(X, Y)); 
    PopupMenu1.Popup(Pt.X, Pt.Y); 
    end; 
end; 
+0

"Apparemment, ce dernier est en vigueur". C'est un contre-intuitif puisque l'événement OnMouseUp n'est plus un événement souris. En fait, il s'agit d'un événement "mouse-down" !!! +1 pour votre réponse très complète – Ampere

+0

@Altar> "... counter intuitive ..." - Je suis d'accord, d'autant plus que le menu contextuel est en fait une réponse à un 'WM_CONTEXTMENU' qui est généré non seulement avec un WM_RBUTTONUP mais aussi avec un WM_NCRBUTTONUP et ' Shift + F10 'et VK_APPS, et, par exemple avec VK_APPS, 'OnKeyUp' est déclenché * avant * le popup est affiché. –