2012-07-15 9 views
14

Oltre a questo post cui risposta accettata rimane molto criptico:TProc <TObject> a TNotifyEvent

@Button1.OnClick := pPointer(Cardinal(pPointer(procedure (sender: tObject) begin ((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!' end)^) + $0C)^; 

mi chiedo che scendessimo sia possibile escogitare un modo più semplice e elegante, simile a:

Button.OnClick := 
        AnonProc2NotifyEvent (
        procedure (Sender: TObject) 
        begin 
         ((Sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!' 
        end 
        ); 

in modo da per raggiungere lo stesso scopo e dove AnonProc2NotifyEvent è un metodo del proprietario di Button con la seguente firma:

TOwnerOfButton = class(TForm) 
    Button: TButton; 
    ... 
private 
    ... 
protected 
    function AnonProc2NotifyEvent(aProc: TProc<TObject>): TNotifyEvent; 
public 
    ... 
end; 

È fattibile e, in caso affermativo, come implementarlo?

+0

Potrebbe essere utile dare un'occhiata a [DSharp.Core.Events.pas] (http://code.google.com/p/delphisorcery/source/browse/trunk/Source/Core/DSharp.Core.Events .pas). –

+0

@Stefan Glienke: Grazie per avermelo ricordato, ho davvero installato DSharp sulla mia scatola e l'ho perso (a mio avviso, non lo uso spesso così spesso) ma credo di seguirlo sin dal suo inizio (Bwt I Sono anche membro di DelphiPraxis, non molto bravo in tedesco, ma cerco di tenere d'occhio la vivace scena tedesca di Delfi). Di sicuro Generics è il mio prossimo passo. Grazie * Stevie * :-) – menjaraz

risposta

21

questo farà il lavoro abbastanza facilmente:

type 
    TNotifyEventWrapper = class(TComponent) 
    private 
    FProc: TProc<TObject>; 
    public 
    constructor Create(Owner: TComponent; Proc: TProc<TObject>); 
    published 
    procedure Event(Sender: TObject); 
    end; 

constructor TNotifyEventWrapper.Create(Owner: TComponent; Proc: TProc<TObject>); 
begin 
    inherited Create(Owner); 
    FProc := Proc; 
end; 

procedure TNotifyEventWrapper.Event(Sender: TObject); 
begin 
    FProc(Sender); 
end; 

function AnonProc2NotifyEvent(Owner: TComponent; Proc: TProc<TObject>): TNotifyEvent; 
begin 
    Result := TNotifyEventWrapper.Create(Owner, Proc).Event; 
end; 

Il parametro Owner in AnonProc2NotifyEvent è così che la durata dell'oggetto involucro può essere gestito. Senza qualcosa del genere si perderebbero istanze di TNotifyEventWrapper.

Passa come Owner, il componente a cui stai collegando l'evento. Per esempio:

Button1.OnClick := AnonProc2NotifyEvent(
    Button1, 
    procedure(Sender: TObject) 
    begin 
    (Sender as TButton).Caption := 'Clicked'; 
    end 
); 

Così, quando il tasto viene distrutto, la TNotifyEventWrapper sarà anche distrutti. L'oggetto wrapper deve vivere almeno fino a quando l'oggetto ai cui eventi è associato. E quindi la scelta di Button1 come proprietario è naturale e ovvia.

+0

Grazie, David! Non mi viene mai in mente che un wrapper funzionerà ed è un buon candidato per la componentizzazione: soluzione concisa, pulita ed elegante. – menjaraz

5

Per riferimento questo che voglio arrivare, ho studiato Barry Kelly 's blog post riferimento nel post prima del SO di cui sopra e si avvicinò con questa soluzione:

function TMainForm.Proc2NotifyEvent(const aProc: TNotifyReference): TNotifyEvent; 
type 
    TVtable = array[0..3] of Pointer; 
    PVtable = ^TVtable; 
    PPVtable = ^PVtable; 
begin 
    TMethod(Result).Code := PPVtable((@aProc)^)^^[3]; 
    TMethod(Result).Data := Pointer((@aProc)^); 
end; 

Ancora criptico ma incapsulato, in modo da facilitare il compito del codificatore rispetto al metodo iniziale.

Ho cercato di riordinare MethRefToMethPtr e MakeNotify e mettere tutto in un metodo.

Si noti che non v'è stato (un leggero) variazione firma del metodo, l'argomento aproc divenne const.

+1

+1 questo è malvagio !! – ComputerSaysNo

+0

Avresti ancora bisogno di fare qualcosa per mantenere in vita l'oggetto che implementa l'interfaccia anon proc. Barry menziona questo dettaglio importante. –

+0

@David Heffernan: Devo tenere un riferimento da qualche parte? – menjaraz

Problemi correlati