2010-07-21 16 views
12

Quando un'azione viene attivata, il "mittente" è sempre l'azione stessa. Di solito è il più utile, ma è in qualche modo possibile scoprire chi ha attivato l'evento onexecute dell'azione?Come posso vedere chi ha attivato un'azione in Delphi?

Esempio

Diciamo che dispone di un modulo con il seguente:

  • 2 pulsanti, chiamati Button1 e Button2
  • 1 dell'aderenza in marcia chiamato actDoStuff

La stessa azione è assegnato a entrambi i pulsanti. È possibile mostrare quale pulsante ho cliccato?

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. 

L'unica soluzione che vedo in questo momento è di non usare la proprietà di azione di pulsanti, ma avente un eventhandler per ogni pulsante, e chiamando actDoStuffExecute() da lì, ma questo tipo di sfida allo scopo di utilizzare le azioni in primo luogo.

Non voglio avere un'azione dedicata per ciascun controllo separato. L'esempio sopra è una versione semplificata del problema che sto affrontando. Ho un menu con un numero variabile di voci di menu (nomi di file), e ogni voce di menu deve fondamentalmente fare la stessa cosa, ad eccezione del caricamento di un altro file. Avere azioni per ciascuna voce di menu sarebbe un po 'sciocco.

+0

Vedi che parametro "Sender: TObject"? ... Questo è pre-compilato per te ... Prova a dare un'occhiata a Sender all'interno della tua funzione. – Fosco

+0

Sì, ma nell'esempio sopra, 'actDoStuff' sarebbe il mittente. Voglio sapere se è stato premuto il pulsante 1 o il pulsante2. –

risposta

18

Provare a utilizzare il ActionComponent proprietà:

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

Usando questo ottengo "Button1" e "Button2" quando si fa clic rispettivamente il primo e secondo pulsante .

+9

Attenzione: cosa succede quando un'azione viene attivata da una scorciatoia da tastiera? –

+0

Grande, esattamente quello che stavo cercando! –

0

Ok, nel frattempo Credo di avere trovato una soluzione praticabile ..

posso avere tutti i comandi utilizzano la stessa azione; Ho solo bisogno di sovrascrivere il loro gestore di eventi OnClick e ho solo bisogno di un singolo gestore per tutti loro.

Sono ancora interessato a sapere se è possibile scoprire quale controllo ha innescato l'azione, ma per la mia applicazione corrente sto usando una soluzione che sia simile al codice qui sotto:

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

Se si stanno scrivendo i gestori di eventi OnClick nei pulsanti, scollegare completamente dall'azione. Sul serio! –

+0

È necessario il collegamento con l'azione se si desidera abilitare/disabilitare tutti i pulsanti in un unico posto (il gestore onupdate dell'azione o dell'elenco azioni). Tuttavia, è necessario prestare attenzione poiché il gestore onclick può essere sovrascritto ad ogni aggiornamento all'azione. –

8

Sapere cosa il pulsante ha attivato il tipo di azione che va contro il punto di utilizzo delle azioni: un'azione può essere attivata da un clic del pulsante o da un clic del menu o da un qualsiasi numero di altre attività dell'utente. Esistono azioni per unificare la gestione dello stato di abilitazione/disabilitazione e la gestione dei clic tra pulsanti e menu.

Se si desidera sapere quale pulsante ha attivato l'azione perché si desidera eseguire un'operazione leggermente diversa, o "assaporare" l'operazione in modo diverso, allora TAction non è la soluzione giusta per ciò che si vuole fare.

+0

Qui proponi che TAction non è la soluzione giusta, ma non proponi un'alternativa. Disabilitare l'azione a livello globale è il modo più semplice per disabilitare le funzioni del programma quando non è consentito eseguire e molto spesso è necessario funzionalità leggermente diverse tra le varie finestre, quindi l'implementazione della propria soluzione non è molto pratica invece di utilizzare una soluzione pre-creata come TAction. Disabilitare la funzione del programma attraverso la disattivazione dell'azione spesso richiede una manutenzione minore (disabilita automaticamente tutti i menu, le barre degli strumenti, ecc. Pertinenti in tutte le finestre che lo utilizzano). – Coder12345

+2

Sono un grande sostenitore di TAction. Quello che sto suggerendo è che un design che cerca di cambiare il comportamento di un evento in base al quale l'elemento dell'interfaccia utente è stato utilizzato per sparare all'evento è un disegno imperfetto. Utilizzare TActions per gestire le azioni in modo uniforme indipendentemente dal trigger. Se davvero hai davvero bisogno che qualcosa di diverso accada quando si fa clic sul pulsante anziché sulla voce di menu, quindi crea un'azione diversa. – dthorpe

0

impostare il tag dei pulsanti come 1, 2, ... ecc e poi:

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

Invece di azioni, basta usare un evento click. Impostare tutti i pulsanti per utilizzare lo stesso gestore di eventi. Idealmente, NON prende il nome dal primo pulsante (puoi rinominarlo).

Ecco il codice:

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

Utilizzare i gestori di eventi OnClick, anche un singolo gestore per più pulsanti, significa perdere la possibilità di abilitarli/disabilitarli tutti in un unico posto (il gestore onupdate dell'azione o dell'elenco azioni). Questo è _unless_ li si combinano con un'azione. L'assegnazione di un'azione sovrascriverà comunque il gestore onclick, quindi dovrai reimpostarlo per tutti i pulsanti coinvolti e probabilmente farlo ogni volta che cambi qualcosa nell'azione. –

+0

Ovviamente questa è ** la risposta giusta! ** Ecco perché c'è "Sender". – Vassilis

1

Ci sono situazioni in cui la stessa azione dovrebbe applicarsi a controlli simili. Il problema con

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

è che quando l'azione viene richiamata da un menu popup, ottieni il nome del menu popup. È possibile utilizzare:

Problemi correlati