2010-07-21 22 views
12

Cuando una acción incluso dispara, el "emisor" es siempre la acción misma. Por lo general, eso es lo más útil, pero ¿es posible de algún modo averiguar quién desencadenó el evento onexecute de la acción?¿Cómo puedo ver quién desencadenó una acción en Delphi?

Ejemplo

Digamos que usted tiene un formulario con los siguientes:

  • 2 botones, llamados Button1 y Button2
  • 1 taction llama actDoStuff

La misma acción está asignado a ambos botones. ¿Es posible mostrar en qué botón hice clic?

Example.dfm

object Form1: TForm1 
    object Button1: TButton 
    Action = actDoStuff 
    end 
    object Button2: TButton 
    Action = actDoStuff 
    Left = 100 
    end 
    object actDoStuff: TAction 
    Caption = 'Do Stuff' 
    OnExecute = actDoStuffExecute 
    end 
end 

Example.pas

unit Example; 
interface 
uses Windows, Classes, Forms, Dialogs, Controls, ActnList, StdCtrls; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Button2: TButton; 
    actDoStuff: TAction; 
    procedure actDoStuffExecute(Sender: TObject); 
    end; 

var 
    Form1: TForm1; 

implementation  
{$R *.dfm} 

procedure TForm1.actDoStuffExecute(Sender: TObject); 
begin 
    ShowMessage('Button X was clicked'); 
end; 

end. 

La única solución que veo en este momento es no utilizar la propiedad de acción de los botones, pero tener un manejador de sucesos para cada botón, y llamar a actDoStuffExecute() desde allí, pero ese tipo de desafía el propósito de usar acciones en primer lugar.

No quiero tener una acción dedicada para cada control por separado tampoco. El ejemplo anterior es una versión simplificada del problema que estoy enfrentando. Tengo un menú con un número variable de elementos de menú (nombres de archivo), y cada ítem del menú básicamente tiene que hacer lo mismo, excepto para cargar otro archivo. Tener acciones para cada elemento del menú sería un poco tonto.

+0

Consulte el parámetro "Sender: TObject"? ... Esto está pre-poblado para usted ... Pruebe echar un vistazo a Sender dentro de su función. – Fosco

+0

Sí, pero en el ejemplo anterior, 'actDoStuff' sería el remitente. Quiero saber si se presionó el botón1 o el botón2. –

Respuesta

18

Trate de usar el ActionComponent propiedad:

ShowMessage((Sender as TAction).ActionComponent.Name); 

El uso de este recibo "Button1" y "Button2" al hacer clic en el botón primero y segundo, respectivamente, .

+9

Cuidado: ¿Qué sucede cuando la acción se desencadena por un atajo de teclado? –

+0

Genial, ¡exactamente lo que estaba buscando! –

0

Ok, mientras tanto creo que he encontrado una solución viable ..

puedo tener todos los controles utilizan la misma acción; Solo tengo que anular su controlador de eventos OnClick, y solo necesito un solo controlador para todos ellos.

Todavía estoy interesado en saber si es posible averiguar el que el control desencadena la acción, pero para mi aplicación actual que estoy usando una solución que es similar al código de abajo:

unit Example; 

interface 

uses 
    Windows, Classes, Forms, Dialogs, Controls, ActnList, StdCtrls; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Button2: TButton; 
    actDoStuff: TAction; 
    procedure actDoStuffExecute(Sender: TObject); 
    procedure ButtonClick(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.actDoStuffExecute(Sender: TObject); 
begin 
    ShowMessage('Button '+TControl(Sender).Name +' was clicked') 
end; 

procedure TForm1.ButtonClick(Sender: TObject); 
begin 
    actDoStuffExecute(Sender) 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Button1.OnClick := ButtonClick; 
    Button2.OnClick := ButtonClick 
end; 

end. 
+1

Si está escribiendo controladores de eventos OnClick en los botones, desvincula amablemente de la acción por completo. ¡Seriamente! –

+0

Necesita el enlace con la acción si desea habilitar/deshabilitar todos los botones en un solo lugar (el manejador de actualización de la acción o de la lista de acciones). Sin embargo, debes tener cuidado ya que el controlador onclick se puede sobrescribir en cada actualización de la acción. –

8

Saber qué El botón dispara la acción, va contra el uso de acciones: una acción puede ser activada por un clic de botón, o un clic de menú, o cualquier cantidad de otras actividades de usuario. Existen acciones para unificar la gestión de estado de habilitar/deshabilitar y hacer clic en el manejo entre botones y menús.

Si desea saber qué botón activó la acción porque desea realizar una operación ligeramente diferente, o "sazonar" la operación de forma diferente, entonces quizás TAction no es la solución adecuada para lo que desea hacer.

+0

Usted propone aquí que TAction no es la solución correcta, sin embargo, no propone una alternativa. Desactivar la acción globalmente es la forma más fácil de deshabilitar las funciones del programa cuando no están permitidas su ejecución y muy a menudo necesita una funcionalidad ligeramente diferente en varias ventanas, por lo que implementar una solución propia no es realmente práctico en lugar de usar una solución prefabricada como TAction. Desactivar la función del programa a través de la acción de deshabilitación a menudo requiere menos mantenimiento más tarde (desactiva todos los menús relevantes, barras de herramientas, etc. automáticamente en todas las ventanas que lo usan). – Coder12345

+2

Soy un gran defensor de TAction. Lo que sugiero es que un diseño que busca cambiar el comportamiento de un evento en función del elemento de UI que se usó para activar el evento es un diseño defectuoso. Use TActions para manejar las acciones de manera uniforme independientemente del desencadenador. Si realmente necesita que ocurra algo diferente cuando se hace clic en el botón en lugar del elemento del menú, entonces cree una acción diferente. – dthorpe

0

establecer la etiqueta de los botones como 1, 2, etc ... y luego:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Button1.OnClick := ButtonClick; 
    Button2.OnClick := ButtonClick; 
end; 

procedure TForm1.ButtonClick(Sender: TObject); 
begin 
    if Sender is TButton then 
    begin 
    Caption := 'Button: ' + IntToStr(TButton(Sender).Tag); 
    end; 
end; 
3

En lugar de acciones, sólo tiene que utilizar un evento de clic. Configure todos los botones para usar el mismo controlador de eventos. Idealmente, NO recibe el nombre del primer botón (puede cambiarle el nombre).

Aquí está el código:

Procedure TMyForm.DestinationButtonClickHandlerThing(Sender: TObject); 
begin 
    if Sender = Btn_ViewIt then 
    begin 
    // View It 
    end 
    else if Sender = Btn_FaxIt then 
    begin 
    // Fax It 
    end 
    else if Sender = Btn_ScrapIt then 
    begin 
    // Scrap It 
    end 
    else 
    .... // error 
    ... 
end; 
+0

El uso de controladores de eventos OnClick, incluso un único controlador para varios botones, significa perder la capacidad de habilitarlos, deshabilitarlos, etc. en un solo lugar (el manejador de actualización de la acción o de la lista de acciones). Es a menos que los combines con una acción. Sin embargo, la asignación de una acción sobrescribirá al controlador onclick, por lo que tendrá que restablecerlo para todos los botones implicados y posiblemente lo haga cada vez que cambie algo en la acción. –

+0

¡Claro que esta es ** la respuesta correcta! ** Es por eso que 'Sender' está ahí. – Vassilis

1

Hay situaciones donde la misma acción debería aplicarse a controles similares. El problema con

ShowMessage((Sender as TAction).ActionComponent.Name); 

es que cuando la acción es invocada por un menú emergente por ejemplo, se obtiene el nombre del menú emergente. Puede usar:

procedure TMyForm.actMyActionExecute(Sender: TObject); 
var 
    LMyControl: TMyControl; 
begin 
    if Screen.ActiveControl.Name = 'MyControl1' then 
    LMyControl = Sender as TMyControl 
    else 
    Exit; 
    // Use the local variable for whatever needed 
end; 
Cuestiones relacionadas