2009-07-26 8 views
0

Ma question fait suite à la réponse à How to create a button with drop-down menu?Comment détecter un clic de souris pour un bouton avec menu déroulant

Je suis en train de reproduire le comportement du « Bouton Office » trouvé dans le coin en haut à gauche de l'interface utilisateur de Mircosoft Office 2007; en particulier lorsque l'utilisateur clique sur le bouton, le menu contextuel apparaît et le bouton est redessiné dans un état "bas". L'image du bouton reste à l'état Down jusqu'à ce que l'utilisateur clique sur la souris dans le menu, OU ailleurs sur le formulaire, OU même en dehors de l'application.

Je dois détecter ce clic de souris pour que je puisse redessiner le bouton dans l'image normale, et si j'utilise ma propre boîte de dialogue comme menu contextuel, pour masquer le menu.

J'utilise D6.
Merci pour tout conseil,
Cordialement,
PhilW.

clarification:

je me rends compte maintenant que la réponse est trivial lorsqu'un TPopupMenu est utilisé, après avoir été sous la compréhension erronée qu'une fois que le menu contextuel a été montré, il a été laissé au sort de l'événement principal boucle. Et j'ai heureusement codé comme tel dans le passé. Plus sage, et un peu embarrassée (mais d'accord avec mes amis), ma question aurait dû être plus précise:

"Comment puis-je détecter ce clic de souris lorsque j'utilise un formulaire de dialogue pour agir comme un TPopUpMenu?"

Désolé pour la confusion.

Répondre

1

Peut-être que je manque quelque chose, mais au moins pour un menu pop-up c'est facile:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    SpeedButton1.AllowAllUp := TRUE; 
    SpeedButton1.GroupIndex := 1; 
end; 

procedure TForm1.SpeedButton1Click(Sender: TObject); 
var 
    CurPos: TPoint; 
begin 
    CurPos := Mouse.CursorPos; 
    PopupMenu1.Popup(CurPos.x, CurPos.y); 
    SpeedButton1.Down := FALSE; 
end; 

Cela fonctionne comme un menu contextuel est affiché en utilisant une boucle de message secondaire, et en cliquant sur l'extérieur de celui-ci ne le rejeter tout comme en cliquant sur un élément de menu. Si vous voulez afficher un formulaire au lieu d'un menu contextuel, vous devez simplement fournir une fonction wrapper qui ne retourne que lorsque le formulaire a été fermé, similaire à Popup() dans le code ci-dessus. Vous pouvez par exemple afficher le formulaire non modal et utiliser la méthode SetCaptureControl() pour gérer tous les événements de la souris, même lorsque le curseur de la souris est en dehors de la zone de formulaire.

Edit:

code pour vous aider à démarrer - il démontre le principe, mais certainement pas complète ou optimale. Au lieu du menu contextuel d'un formulaire est affiché:

procedure TForm1.SpeedButton1Click(Sender: TObject); 
var 
    PtLeftTop: TPoint; 
begin 
    PtLeftTop := ClientToScreen(Point(SpeedButton1.Left + SpeedButton1.Width, 
    SpeedButton1.Top + SpeedButton1.Height)); 
    TForm2.ShowFormAsPopup(PtLeftTop); 
    SpeedButton1.Down := FALSE; 
end; 

Le formulaire a le code suivant:

type 
    TForm2 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    procedure FormKeyDown(Sender: TObject; var Key: Word; 
     Shift: TShiftState); 
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton; 
     Shift: TShiftState; X, Y: Integer); 
    procedure FormDeactivate(Sender: TObject); 
    public 
    class procedure ShowFormAsPopup(ATopLeft: TPoint); 
    end; 

// boilerplate snipped 

class procedure TForm2.ShowFormAsPopup(ATopLeft: TPoint); 
var 
    Form2: TForm2; 
    OldDeactivate: TNotifyEvent; 
begin 
    Form2 := TForm2.Create(nil); 
    try 
    OldDeactivate := Application.OnDeactivate; 
    try 
     Application.OnDeactivate := Form2.FormDeactivate; 

     Form2.Left := ATopLeft.x; 
     Form2.Top := ATopLeft.y; 
     Form2.Show; 
     SetCaptureControl(Form2); 
     while Form2.Visible do 
     Application.ProcessMessages; 
    finally 
     Application.OnDeactivate := OldDeactivate; 
    end; 
    finally 
    Form2.Release; 
    end; 
end; 

procedure TForm2.FormCreate(Sender: TObject); 
begin 
    KeyPreview := TRUE; 
end; 

procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    if Key = VK_ESCAPE then 
    Visible := FALSE; 
end; 

procedure TForm2.FormMouseDown(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    ScreenPos: TPoint; 
begin 
    ScreenPos := ClientToScreen(Point(X, Y)); 
    if (ScreenPos.X < Left) or (ScreenPos.Y < Top) 
    or (ScreenPos.X > Left + Width) or (ScreenPos.Y > Top + Height) 
    then begin 
    Visible := FALSE; 
    end; 
end; 

procedure TForm2.FormDeactivate(Sender: TObject); 
begin 
    Visible := FALSE; 
end; 
+0

Au Contraire, il était moi. Il a fallu beaucoup de temps pour comprendre votre réponse, jusqu'à ce que je réalise que l'instruction Popup a renvoyé le contrôle à la ligne immédiatement après (!). J'ai clarifié ma question. – PhilW

+0

Fantastique! Appréciez beaucoup les conseils et le code. Réponse acceptée avec merci. – PhilW

Questions connexes