Drop down menu for TButton

前端 未结 2 2040
栀梦
栀梦 2021-02-06 07:06

I am trying to simulate a drop down menu for a TButton, as shown below:

procedure DropMenuDown(Control: TControl; PopupMenu: TPopupMenu);
var
  APoint: TPoint;
b         


        
相关标签:
2条回答
  • 2021-02-06 07:50

    Following our (Vlad & I) discussion, you use a variable to know when the popup was last opened to choose if you display the popupmenu or cancel the mouse event:

    unit Unit4;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.StdCtrls;
    
    type
      TForm4 = class(TForm)
        PopupMenu1: TPopupMenu;
        Button1: TButton;
        fgddfg1: TMenuItem;
        fdgdfg1: TMenuItem;
        procedure FormCreate(Sender: TObject);
        procedure Button1Click(Sender: TObject);
        procedure Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
      private
        { Private declarations }
        cMenuClosed: Cardinal;
    
      public
        { Public declarations }
      end;
    
    var
      Form4: TForm4;
    
    implementation
    
    {$R *.dfm}
    
    procedure DropMenuDown(Control: TControl; PopupMenu: TPopupMenu);
    var
      APoint: TPoint;
    begin
      APoint := Control.ClientToScreen(Point(0, Control.ClientHeight));
      PopupMenu.Popup(APoint.X, APoint.Y);
    end;
    
    procedure TForm4.Button1Click(Sender: TObject);
    begin
      DropMenuDown(Button1, PopupMenu1);
      cMenuClosed := GetTickCount;
    end;
    
    procedure TForm4.Button1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    begin
      if (Button = mbLeft) and not ((cMenuClosed + 100) < GetTickCount) then
      begin
        ReleaseCapture;
      end;
    end;
    
    procedure TForm4.FormCreate(Sender: TObject);
    begin
      cMenuClosed := 0;
    end;
    
    end.
    
    0 讨论(0)
  • 2021-02-06 07:57

    After reviewing the solution provided by Whiler & Vlad, and comparing it to the way WinSCP implements the same thing, I'm currently using the following code:

    unit ButtonMenus;
    interface
    uses
      Vcl.Controls, Vcl.Menus;
    
    procedure ButtonMenu(Control: TControl; PopupMenu: TPopupMenu);
    
    implementation
    
    uses
      System.Classes, WinApi.Windows;
    
    var
      LastClose: DWord;
      LastPopupControl: TControl;
      LastPopupMenu: TPopupMenu;
    
    procedure ButtonMenu(Control: TControl; PopupMenu: TPopupMenu);
    var
      Pt: TPoint;
    begin
      if (Control = LastPopupControl) and (PopupMenu = LastPopupMenu) and (GetTickCount - LastClose < 100) then begin
        LastPopupControl := nil;
        LastPopupMenu := nil;
      end else begin
        PopupMenu.PopupComponent := Control;
        Pt := Control.ClientToScreen(Point(0, Control.ClientHeight));
        PopupMenu.Popup(Pt.X, Pt.Y);
        { Note: PopupMenu.Popup does not return until the menu is closed }
        LastClose := GetTickCount;
        LastPopupControl := Control;
        LastPopupMenu := PopupMenu;
      end;
    end;
    
    end.
    

    It has the advantage of not requiring any code changes to the from, apart from calling ButtonMenu() in the onClick handler:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ButtonMenu(Button1, PopupMenu1);
    end;
    
    0 讨论(0)
提交回复
热议问题