2008-12-11 8 views
14

अगर मैं एक ईवेंट हैंडलर संकलक के साथ शिकायत पर एक बंद उपयोग करने का प्रयास:मैं एक ईवेंट हैंडलर (यानी, TButton OnClick) पर एक बंद उपयोग कर सकते हैं

असंगत प्रकार: "विधि सूचक और नियमित रूप से प्रक्रिया"

जो मैं समझता हूं .. लेकिन क्या विधि पॉइंटर्स पर क्लोजर का उपयोग करने का कोई तरीका है? और कैसे परिभाषित किया जा सकता है?

जैसे:

Button1.Onclick = procedure(sender : tobject) begin ... end; 

धन्यवाद!

उत्तर

10
@Button1.OnClick := pPointer(Cardinal(pPointer(procedure (sender: tObject) 
begin 
    ((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!' 

end)^) + $0C)^; 

डेल्फी 2010 में works

+1

@ माजिन: यह चालाक है और यह काम करता है क्योंकि एक अज्ञात विधि एक अज्ञात वर्ग में एम्बेडेड है। भविष्य की संगतता पर संदर्भित आलेख में बैरी केली से टिप्पणी को पढ़ना सुनिश्चित करें, और बैरी केली द्वारा यह पोस्ट: http://blog.barrkel.com/2010/01/using-anonymous-methods-in-method.html –

+1

यह समाधान Win32 प्लेटफ़ॉर्म पर काम करता है लेकिन Win64 नहीं। –

+1

@ChauCheeYang सबसे अधिक संभावना है क्योंकि $ 0C आकारऑफ (सूचक) * 3 होना चाहिए .. –

5

एक उत्कृष्ट सवाल।

जहां तक ​​मुझे पता है, डेल्फी के वर्तमान संस्करण में ऐसा करना संभव नहीं है। यह बहुत दुर्भाग्यपूर्ण है क्योंकि उन अज्ञात प्रक्रियाओं को ऑब्जेक्ट के ईवेंट हैंडलर को तेज़ी से स्थापित करने के लिए बहुत अच्छा होगा, उदाहरण के लिए जब xUnit प्रकार के स्वचालित परीक्षण ढांचे में परीक्षण फिक्स्चर सेट अप करते हैं।

1:

वहाँ CodeGear इस सुविधा को लागू करने के लिए दो तरीके से किया जाना चाहिए गुमनाम तरीकों के निर्माण के लिए अनुमति दें। कुछ ऐसा:

Button1.OnClick := procedure(sender : tobject) of object begin 
    ... 
end; 

यहां समस्या यह है कि अज्ञात विधि के लिए स्वयं सूचक के रूप में क्या रखना है। कोई उस ऑब्जेक्ट के स्वयं पॉइंटर का उपयोग कर सकता है जिससे अज्ञात विधि बनाई गई थी, लेकिन फिर कोई ऑब्जेक्ट संदर्भ से केवल अज्ञात विधियां बना सकता है। अज्ञात विधि को रखने के लिए दृश्यों के पीछे एक डमी ऑब्जेक्ट बनाना एक बेहतर विचार हो सकता है।

2: वैकल्पिक रूप से, कोई ईवेंट प्रकारों को प्रक्रियाओं और प्रक्रियाओं को स्वीकार करने की अनुमति दे सकता है, जब तक वे परिभाषित हस्ताक्षर साझा करते हैं। इस तरह आप ईवेंट हैंडलर को जिस तरह से चाहते हैं उसे बना सकते हैं:

Button1.OnClick := procedure(sender : tobject) begin 
    ... 
end; 

मेरी आंखों में यह सबसे अच्छा समाधान है।

+0

एक विधि एक ही तर्क के साथ एक प्रक्रिया के रूप में ही बुला हस्ताक्षर नहीं है। तरीके हमेशा स्वयं को "छिपा" तर्क के रूप में पास करते हैं। –

+1

हां, ज़ाहिर है।लेकिन मुझे कोई कारण नहीं दिख रहा है कि क्यों संकलक "दृश्यों के पीछे" दोनों मामलों को संभालने में सक्षम नहीं होना चाहिए। उदाहरण के लिए यदि किसी विधि की अपेक्षा की जाती है तो अज्ञात प्रक्रिया के आस-पास एक डमी क्लास रैपर बना सकता है। –

+1

यह पैटर्न जावास्क्रिप्ट पायथन जैसे गतिशील भाषाओं में इतना आम है। –

4

पिछले डेल्फी संस्करणों में आप मापदंडों के छिपे हुए स्वयं सूचक जोड़कर ईवेंट हैंडलर के रूप में एक नियमित प्रक्रिया का उपयोग कर सकता है और मुश्किल यह टाइपकास्ट:

procedure MyFakeMethod(_self: pointer; _Sender: TObject); 
begin 
    // do not access _self here! It is not valid 
    ... 
end; 

... 

var 
    Meth: TMethod; 
begin 
    Meth.Data := nil; 
    Meth.Code := @MyFakeMethod; 
    Button1.OnClick := TNotifyEvent(Meth); 
end; 

मुझे यकीन है कि इसके बाद के संस्करण वास्तव में संकलित नहीं कर रहा हूँ, लेकिन यह देना चाहिए आप सामान्य विचार है। मैंने पहले यह किया है और यह नियमित प्रक्रियाओं के लिए काम करता है। चूंकि मुझे नहीं पता कि संकलक बंद करने के लिए कौन सा कोड उत्पन्न करता है, मैं यह नहीं कह सकता कि यह उनके लिए काम करेगा या नहीं।

+0

मैंने अभी परीक्षण किया है, और यह बंद होने के साथ काम नहीं करता है, लेकिन मुझे कुछ याद आ सकता है। –

1

इसका आसान और अधिक प्रपत्र घटना प्रकारों को प्रबंधित करने के लिए नीचे का विस्तार करने के।

प्रयोग

procedure TForm36.Button2Click(Sender: TObject); 
var 
    Win: TForm; 
begin 
    Win:= TForm.Create(Self); 
    Win.OnClick:= TEventComponent.NotifyEvent(Win, procedure begin ShowMessage('Hello'); Win.Free; end); 
    Win.Show; 
end; 

कोड

unit AnonEvents; 

interface 
uses 
    SysUtils, Classes; 

type 
    TEventComponent = class(TComponent) 
    protected 
    FAnon: TProc; 
    procedure Notify(Sender: TObject); 
    class function MakeComponent(const AOwner: TComponent; const AProc: TProc): TEventComponent; 
    public 
    class function NotifyEvent(const AOwner: TComponent; const AProc: TProc): TNotifyEvent; 
    end; 

implementation 

{ TEventComponent } 

class function TEventComponent.MakeComponent(const AOwner: TComponent; 
    const AProc: TProc): TEventComponent; 
begin 
    Result:= TEventComponent.Create(AOwner); 
    Result.FAnon:= AProc; 
end; 

procedure TEventComponent.Notify(Sender: TObject); 
begin 
    FAnon(); 
end; 

class function TEventComponent.NotifyEvent(const AOwner: TComponent; 
    const AProc: TProc): TNotifyEvent; 
begin 
    Result:= MakeComponent(AOwner, AProc).Notify; 
end; 

end. 
संबंधित मुद्दे

 संबंधित मुद्दे