2012-07-15 21 views
14

Tiếp tục để post này có chấp nhận câu trả lời vẫn còn rất khó hiểu:TProc <TObject> để TNotifyEvent

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

Tôi tự hỏi thời tiết có thể đưa ra một đơn giản nhất và cách thanh lịch giống như:

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

như vậy là để đạt được mục đích tương tự và nơi AnonProc2NotifyEvent là phương thức của chủ sở hữu Nút có chữ ký sau:

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

Điều đó có khả thi và nếu có thì làm thế nào để thực hiện nó?

+0

Bạn có thể muốn xem [DSharp.Core.Events.pas] (http://code.google.com/p/delphisorcery/source/browse/trunk/Source/Core/DSharp.Core.Events .pas). –

+0

@Stefan Glienke: Cảm ơn bạn đã nhắc nhở tôi, tôi đã cài đặt DSharp trên hộp và tôi bỏ qua nó (để loại bỏ, tôi không thường xuyên sử dụng nó) nhưng tôi tin rằng tôi sẽ theo dõi nó kể từ khi thành lập (Bwt I) '' cũng là thành viên của DelphiPraxis, không giỏi tiếng Đức nhưng cố gắng theo dõi cảnh tượng Delphi của Đức). Để chắc chắn Generics là bước tiếp theo của tôi. Cảm ơn bạn * Stevie * :-) – menjaraz

Trả lời

21

này sẽ thực hiện công việc dễ dàng đủ:

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; 

Các Owner tham số trong AnonProc2NotifyEvent là cho nên thời gian của đối tượng wrapper có thể được quản lý. Nếu không có thứ gì đó như thế bạn sẽ làm rò rỉ các trường hợp của TNotifyEventWrapper.

Chuyển thành Owner, thành phần mà bạn đang kết nối sự kiện. Ví dụ:

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

Vì vậy, khi nút bị hủy, TNotifyEventWrapper cũng sẽ bị hủy. Đối tượng bao bọc phải sống ít nhất chừng nào đối tượng có sự kiện được liên kết. Và do đó, sự lựa chọn của Button1 là chủ sở hữu là tự nhiên và rõ ràng nhất.

+0

Cảm ơn bạn David! Nó không bao giờ vượt qua tâm trí của tôi rằng một wrapper sẽ làm và nó là một ứng cử viên tốt để thành phần: Concise, sạch sẽ và thanh lịch giải pháp. – menjaraz

5

Để tham khảo này những gì tôi đang nhận được tại, tôi đã học Barry Kelly 's blog post tham chiếu trong bài trước SO nêu trên và đã đưa ra giải pháp này:

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; 

Tuy nhiên khó hiểu nhưng encapsuled, vì vậy giảm bớt sự nhiệm vụ của coder so với phương thức ban đầu.

Tôi cố gắng để dọn MethRefToMethPtrMakeNotify và đặt nó tất cả trong một phương pháp.

Chú ý rằng có (một chút) thay đổi chữ ký của phương pháp, lập luận aProc trở thành const.

+1

+1 điều này là xấu xa !! – ComputerSaysNo

+0

Bạn vẫn cần phải làm điều gì đó để giữ cho đối tượng thực hiện giao diện anon proc. Barry đề cập đến chi tiết quan trọng đó. –

+0

@ David Heffernan: Tôi có nên giữ tài liệu tham khảo ở đâu đó không? – menjaraz

Các vấn đề liên quan