Delphi 单击t按钮时如何显示TPopupMenu?

Delphi 单击t按钮时如何显示TPopupMenu?,delphi,button,cursor-position,popupmenu,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 ; p

我想在单击按钮时显示弹出菜单,但此过程在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 Error]Form1.pas(398):E2197常量对象不能作为var参数传递

单击按钮时,是否有更好的方式显示弹出菜单?

只需执行即可

procedure TForm1.Button1Click(Sender: TObject);
var
  pnt: TPoint;
begin
  if GetCursorPos(pnt) then
    PopupMenu1.Popup(pnt.X, pnt.Y);
end;
再讨论一下 如果出于某种原因需要使用onmoseup
,您可以这样做

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;
// 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;    
你的代码不起作用,因为

  • ClientToScreen
    是带有签名的Windows API的函数

    function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
    
    function TControl.ClientToScreen(const Point: TPoint): TPoint;
    
    但是,还有一个带有签名的
    TControl.ClientToScreen

    function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): BOOL;
    
    function TControl.ClientToScreen(const Point: TPoint): TPoint;
    
    因此,如果您在一个类方法中,该类是
    TControl
    的decentant,
    ClientToScreen
    将引用后者。若否,则指前者。当然,这一个需要知道我们从哪个窗口转换坐标

  • 另外,如果你申报

    var mb1: TMouseButton
    
    作为参数,则仅接受类型为
    TMouseButton
    的变量。但是我看不出有任何理由希望您的
    ShowPopupMenuEx
    函数具有此签名。事实上,我认为根本不需要这样一个函数

  • 替代方案 我上面的代码将在光标位置弹出菜单。如果您需要固定相对于按钮一角的点,您可以这样做

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

    此错误是因为您的代码调用的是
    Windows.ClientToScreen
    函数,而不是
    t控制.客户端到屏幕
    功能

    试试这样的

    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;
    
    或者在
    Tform1
    类中声明您的过程
    ShowPopupMenuEx
    ,并将其工作。

    对于TToolButton也同样如此 (假设TToolButton
    Style
    tbsDropDown
    。)

    根据我的经验,我发现我更希望在单击整个按钮时显示下拉菜单,而不仅仅是下拉箭头(⯆).

    为了实现这一点,根据@Andreas在上述替代方案下的代码, 只需添加
    Down:=True
    属性,如下所示:

    过程TForm1.ToolButton1Click(发送方:TObject);
    开始
    使用工具按钮1,客户端到屏幕(点(0,高度))执行以下操作
    开始
    向下:=真;
    下拉菜单。弹出窗口(X,Y);
    结束;
    结束;
    

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

    当有
    t按钮时,使用
    Self.ClientToScreen
    是相当愚蠢的。而且,我用八分钟击败了你…@Andreas试试我发布的代码,你就会明白为什么我调用
    Self.ClientToScreen
    而不是
    t按钮.ClientToScreen
    @RRUZ:对不起,我看不到。但我确实认为在我提交帖子八分钟后在帖子中发布所有信息的子集是不礼貌的。对不起,我感觉不到任何不同…@Andreas:你的代码使用当前光标位置,而RRUZ的代码使用按钮的左下角。因此有一个不同的e、 IMHO RRUZ的版本看起来更好。-)为什么要在shoppopumenuex()过程中使用var参数?哎呀,这是我的错误,对不起。