单击TButton时如何显示TPopupMenu?

时间:2010-10-21 11:39:37

标签: delphi button cursor-position popupmenu

我想在单击按钮时显示弹出菜单,但此过程在Delphi XE中有错误。

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;

当点击按钮显示此错误时:

  

[DCC错误] Form1.pas(205):E2010不兼容的类型:'HWND'和'TPoint'
  [DCC错误] Form1.pas(398):E2197常量对象不能作为var参数传递   [DCC错误] Form1.pas(398):E2197常量对象不能作为var参数传递

单击按钮时,show popupmenu有没有更好的方法?

3 个答案:

答案 0 :(得分:22)

只做

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

更多讨论

如果由于某种原因需要使用OnMosuseUp,您可以

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;

您的代码无效,因为

  1. ClientToScreen是带有签名的Windows API的函数

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

    但是,还有一个带有签名的TControl.ClientToScreen

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

    因此,如果你是一个类方法,那么作为TControlClientToScreen的后代的类将引用后者。如果没有,它将参考前一个。当然,这一个需要知道我们要从哪个窗口转换坐标!

  2. 此外,如果您声明

    var mb1: TMouseButton
    

    作为参数,只接受TMouseButton类型的变量。但我看不出你为什么想要ShowPopupMenuEx函数的签名。事实上,我认为根本不需要这样的功能......

  3. 替代

    上面的代码会弹出光标位置的菜单。如果您需要相对于按钮的一角固定点,则可以执行

    // 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;    
    

答案 1 :(得分:5)

此错误是因为您的代码正在调用Windows.ClientToScreen函数而不是 TControl.ClientToScreen功能

尝试这样的事情

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;

或在ShowPopupMenuEx课程中声明您的Tform1程序,然后就可以了。

答案 2 :(得分:0)

类似地用于TToolButton

(假设TToolButton StyletbsDropDown ...)

根据我的经验,我发现很多时候,我宁愿单击整个按钮时显示的下拉菜单,而不仅仅是 下拉箭头 (⯆)。

要实现此目标,请根据上面An Alternative下@Andreas的代码, 只需添加Down := True属性,如下所示:

procedure TForm1.ToolButton1Click(Sender: TObject);
begin
  with ToolButton1, ClientToScreen(Point(0, Height)) do
  begin
    Down := True;
    DropdownMenu.Popup(X, Y);
  end;
end;

这也模拟了按钮背景的显示行为。