2010-10-21 34 views
4

Je veux afficher un menu contextuel lorsque vous cliquez sur un bouton, mais cette procédure comporte une erreur dans Delphi XE.Comment afficher un TPopupMenu lorsque vous cliquez sur un TButton?

procedure ShowPopupMenuEx(var mb1:TMouseButton;var X:integer;var Y:integer;var pPopUP:TPopupMenu); 
var 
    popupPoint : TPoint; 
begin 
    if (mb1 = mbLeft) then begin 
    popupPoint.X := x ; 
    popupPoint.Y := y ; 
    popupPoint := ClientToScreen(popupPoint); //Error Here 
    pPopUP.Popup(popupPoint.X, popupPoint.Y) ; 
    end; 
end; 

procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); 
begin 
    ShowPopupMenuEx(button,Button1.Left,Button1.Top,PopupMenu1); //Error Here 
end; 

lorsque le bouton cliquez sur Afficher cette erreur:

[Erreur DCC] Form1.pas (205): E2010 types incompatibles: 'HWND' et 'TPoint'
[Erreur DCC] Form1. pas (398): E2197 objet constante ne peut pas être transmis en tant que paramètre var
[erreur CDC] Form1.pas (398): E2197 objet constante ne peut pas être transmis en tant que paramètre var

y at-il meilleure façon f ou afficher le menu contextuel, lorsque vous cliquez sur un bouton?

+0

Pourquoi utilisez-vous les paramètres var pour ShopPopupMenuEx() -procedure? – Vegar

+0

oups, c'est mon erreur, désolé. – User

Répondre

16

Il suffit de faire

procedure TForm1.Button1Click(Sender: TObject); 
var 
    pnt: TPoint; 
begin 
    if GetCursorPos(pnt) then 
    PopupMenu1.Popup(pnt.X, pnt.Y); 
end; 

Un peu plus de discussion

Si pour une raison quelconque besoin d'utiliser OnMosuseUp, vous pouvez le faire

procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
var 
    pnt: TPoint; 
begin 
    if (Button = mbLeft) and GetCursorPos(pnt) then 
    PopupMenu1.Popup(pnt.X, pnt.Y); 
end; 

Votre code ne fonctionne pas parce que

  1. ClientToScreen est une fonction de l'API Windows avec la signature

    function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL; 
    

    Mais, il y a aussi une TControl.ClientToScreen avec la signature

    function TControl.ClientToScreen(const Point: TPoint): TPoint; 
    

    Par conséquent, si vous êtes dans une méthode de classe, la classe étant un le défendeur de TControl, ClientToScreen se référera à ce dernier. Sinon, il se référera à l'ancien. Et celui-ci, bien sûr, a besoin de savoir de quelle fenêtre nous sommes pour transformer les coordonnées!

  2. Aussi, si vous déclarez

    var mb1: TMouseButton 
    

    comme paramètre, seule une variable de type TMouseButton sera acceptée. Mais je ne vois pas pourquoi vous voudriez cette signature de votre fonction ShowPopupMenuEx. En fait, je ne vois pas besoin d'une telle fonction du tout ...

Une alternative

Mon code dans le menu ci-dessus apparaitre à la pos du curseur.Si vous avez besoin de fixer le point par rapport à un coin du bouton, à la place, vous pouvez le faire

// Popup at the top-left pixel of the button 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with Button1.ClientToScreen(point(0, 0)) do 
    PopupMenu1.Popup(X, Y); 
end; 

// Popup at the bottom-right pixel of the button 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with Button1.ClientToScreen(point(Button1.Width, Button1.Height)) do 
    PopupMenu1.Popup(X, Y); 
end; 

// Popup at the bottom-left pixel of the button 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with Button1.ClientToScreen(point(0, Button1.Height)) do 
    PopupMenu1.Popup(X, Y); 
end;  
4

cette erreur est parce que votre code appelle la fonction Windows.ClientToScreen au lieu de la fonction TControl.ClientToScreen

essayer quelque chose comme celui-ci

procedure TForm6.Button2Click(Sender: TObject); 
var 
    pt : TPoint; 
begin 
    pt.x := TButton(Sender).Left + 1; 
    pt.y := TButton(Sender).Top + TButton(Sender).Height + 1; 
    pt := Self.ClientToScreen(pt); 
    PopupMenu1.popup(pt.x, pt.y); 
end; 

ou déclarer votre procédure ShowPopupMenuEx à l'intérieur de votre classe et Tform1 fonctionnera.

+0

Il est plutôt stupide d'utiliser 'Self.ClientToScreen' quand il y a un' TButton.ClientToScreen'. Aussi, je vous ai battu avec huit minutes ... –

+0

@Andreas essayer le code que j'ai posté, et vous comprendrez pourquoi j'appelle 'Self.ClientToScreen' au lieu de' TButton.ClientToScreen' – RRUZ

+0

@RRUZ: Je suis désolé. Je ne le vois pas. –