2012-05-15 13 views
6

estoy tratando de simular un menú desplegable para un TButton, como se muestra a continuación:Desplegar menú para TButton

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 TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton; 
    Shift: TShiftState; X, Y: Integer); 
begin 
    if Button = mbLeft then 
    begin 
    DropMenuDown(Button1, PopupMenu1); 
    // ReleaseCapture; 
    end; 
end; 

El problema es que cuando el menú se deja caer hacia abajo, si hago clic en el botón otra vez quisiera que el menú se cerrara, pero en lugar de eso, vuelve a caer.

Estoy buscando una solución específicamente para Delphi genérico TButton sin equivalente de terceros.

Respuesta

3

Después de nuestra discusión (Vlad & I), se utiliza una variable para saber cuando se abrió el pasado la ventana emergente para elegir si visualiza el popupmenu o cancelar el evento de ratón:

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

¿Está el PopupListEx no es una exageración aquí? Sabemos que el menú está cerrado justo después de la línea DropMenuDown (ya que la ventana emergente es sincrónica), o me perdí algo? – Vlad

+0

si hace clic en el botón ... luego, espera n segundos sin hacer nada ... y luego ... decide presionar nuevamente el botón ... antes de presionarlo, ya que no ha hecho nada ... la ventana emergente todavía está abierta? entonces, si 'cMenuClosed: = GetTickCount;' justo después de 'DropMenuDown (Button1, PopupMenu1);' el caso que acabo de explicar no debería funcionar ... – Whiler

+2

Lo que quise decir es esto: 'procedure TForm1.Button1Click (Sender: TObject); begin DropMenuDown (Button1, PopupMenu1); cMenuClosed: = GetTickCount; final; procedure TForm1.Button1MouseDown (Sender: TObject; Botón: TMouseButton; Shift: TShiftState; X, Y: Entero); begin if (Button = mbLeft) and not ((cMenuClosed + 100) Vlad

3

Después de revisar la solución proporcionada por Whiler & Vlad, y comparándolo con la forma WinSCP implementa la misma cosa, actualmente estoy usando el siguiente código:

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. 

tiene la ventaja de no requerir ningún cambio de código a partir de la, además de callos ng ButtonMenu() en el manejador de onClick:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ButtonMenu(Button1, PopupMenu1); 
end; 
+0

Esta es la solución mejor y más genérica. Ver también [esta respuesta] (http://stackoverflow.com/a/27216656/757830). +1 – NGLN

Cuestiones relacionadas