2012-12-19 42 views
7

प्रिय डेल्फी प्रोग्रामर,एक-शॉट टाइमर

मैं मदद कैसे एक शॉट टाइमर (कोई जीयूआई, तो VCL टाइमर सवाल से बाहर) लिखने के लिए ...

मुझे समझाता हूँ के लिए देख रहा हूँ थोड़ा और।

मेरी कोड में (VCL टाइमर के साथ समझा लेकिन इस विशेष परियोजना में मैं कोई फॉर्म नहीं है):

  1. कॉल एक procedure जो सीरियल पोर्ट
  2. पर एक चार भेजने के एक एक्स राशि के साथ एक टाइमर सक्षम करें Interval

OnTimer घटना में:

मैं एक कोड है जो एक चार भेज तो वें अक्षम ई टाइमर खुद को कभी भी निष्पादित नहीं किया जाएगा।

समस्या यह है कि मुझे इन टाइमर गतिशील बनाने की आवश्यकता है। मैंने इसे निष्क्रिय करने के लिए "ऑनटाइमर ईवेंट" में SetTimer() फ़ंक्शन KillTimer() के बारे में सोचा था (इसे मुक्त करें)।

क्या यह एक अच्छा (सुरक्षित) तरीका है?

धन्यवाद!

+0

मैंने कुछ समय पहले ['कुछ समान '] (http://stackoverflow.com/q/10468787/960757) बनाया है। आपका दृष्टिकोण अच्छा लगता है, लेकिन ध्यान दें, कि यदि आप एक समय में एक से अधिक टाइमर शुरू करेंगे, तो आपको अंतर करने की आवश्यकता होगी, उनमें से एक ने उस टाइमआउट को निकाल दिया है यदि आप उन सभी के लिए एक सामान्य कॉलबैक प्रो का उपयोग करते हैं। – TLama

+0

मैंने पढ़ा है कि 'SetTimer()' फ़ंक्शन आप टाइमर को "अनन्य आईडी" डाल सकते हैं और उनकी आईडी – ELCouz

+0

से मार सकते हैं हां, मैं यही कोड में कर रहा हूं। मैं टाइमर आईडी और प्रक्रियाओं का संग्रह संग्रहीत कर रहा हूं जिनकी टाइमर अंतराल समाप्त होने पर किया जाना चाहिए। जब ऐसा होता है, तो मैं उस संग्रह में एक टाइमर की आईडी द्वारा किसी आइटम के लिए खोज करता हूं जो समाप्त हो जाता है और यदि यह पाया जाता है, तो मैं टाइमर को मारता हूं, उस प्रक्रिया को निष्पादित करता हूं और उस आइटम को संग्रह से हटा देता हूं। – TLama

उत्तर

14

क्या टाइमर ईवेंट के अंदर से टाइमर को मारना सुरक्षित है?

हाँ, यह पूरी तरह से सुरक्षित है।

सरलतम शॉट शॉट टाइमर को कैसे कार्यान्वित करें?

एक 1 सेकंड एक शॉट टाइमर का सबसे आसान कार्यान्वयन इस, लेकिन टिप्पणी है, कि अगर आप उनमें से अधिक शुरू करते हैं, आप को अलग करने के जो उनमें से एक अपने अंतराल बीत सक्षम नहीं होगा:

procedure TimerProc(hwnd: HWND; uMsg: UINT; idEvent: UINT_PTR; 
    dwTime: DWORD); stdcall; 
begin 
    KillTimer(0, idEvent); 
    ShowMessage('I''m done!'); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    SetTimer(0, 0, 1000, @TimerProc); 
end; 
+2

+1 आपका उत्तर उस से स्पष्ट और सटीक नहीं हो सकता है! धन्यवाद! उम्मीद है कि यह किसी और की मदद करें :) – ELCouz

+2

आपका स्वागत है! बस एक sidenote; जब हम 'टीटीमर 'वर्ग के बारे में बात करेंगे और' ओनटाइमर 'घटना से अक्सर उपयोग किए जाने वाले अक्षम होते हैं, तो आंतरिक रूप से वही होता है। असल में, जब भी आप 'सक्षम' संपत्ति की स्थिति बदलते हैं, टाइमर को पहले 'किलटाइमर' फ़ंक्शन द्वारा मार दिया जाता है और नया विकल्प वैकल्पिक रूप से 'SetTimer' फ़ंक्शन द्वारा बनाया जाता है। तो, यह 'OnTimer' ईवेंट से' KillTimer' के वास्तविक उपयोग का एक उदाहरण है। – TLama

+4

सवाल कहता है कि कोई जीयूआई नहीं है, इस मामले में आप जरूरी नहीं मान सकते कि वहां एक संदेश लूप होगा। मूल विंडोज टाइमर को संदेश लूप की आवश्यकता होती है। –

2

मल्टीमीडिया टाइमर एपीआई एक शॉट टाइमर के लिए समर्थन प्रदान करता है। लाभ यह है कि समय SetTimer/KillTimer समाधान से अधिक सटीक है और आप इसे अंतराल < 50 एमएस के साथ उपयोग कर सकते हैं। यह कीमत पर आता है, क्योंकि कॉलबैक मुख्य धागे के संदर्भ में वापस नहीं आता है। यहाँ मल्टीमीडिया टाइमर एपीआई का उपयोग कर एक शॉट टाइमर के अपने कार्यान्वयन है:

unit MMTimer; 

interface 
uses windows, Classes, mmsystem, SysUtils; 
TOneShotCallbackEvent = procedure (const UserData: Pointer) of object; 

(* 
    The MMOneShotCallback function calls the Callback after the Interval passed. 
    ** Attention: ** 
    The Callback is not called within the context of the main thread. 
*) 

type TMMOneShotTimer = class(TObject) 
    private 
    FTimeCaps: TTimeCaps; 
    FResult: Integer; 
    FResolution: Cardinal; 
    public 
    constructor Create; 
    function MMOneShotCallback(const Interval: Cardinal; UserData: Pointer; Callback: TOneShotCallbackEvent): Boolean; 
    property Result: Integer read FResult; 
    property Resolution: Cardinal read FResolution; 
end; 
implementation 
type 
    TOneShotCallbackData = record 
    Callback: TOneShotCallbackEvent; 
    UserData: Pointer; 
    end; 
    POneShotCallbackData = ^TOneShotCallbackData; 

procedure OneShotCallback(TimerID, Msg: UINT; 
        dwUser, dw1, dw2: DWord); pascal; 
var pdata: POneShotCallbackData; 
begin 
    pdata := Pointer(dwUser); 
    pdata.Callback(pdata.UserData); 
    FreeMemory(pdata); 
end; 

constructor TMMOneShotTimer.Create; 
begin 
    FResult := timeGetDevCaps(@FTimeCaps, SizeOF(FTimeCaps)); 
    Assert(FResult=TIMERR_NOERROR, 'Call to timeGetDevCaps failed'); 
    FResolution := FTimeCaps.wPeriodMin; 
    FResult := timeBeginPeriod(FResolution); 
    Assert(FResult=TIMERR_NOERROR, 'Call to timeBeginPeriod failed'); 
end; 

function TMMOneShotTimer.MMOneShotCallback(const Interval: Cardinal; UserData: Pointer; Callback: TOneShotCallbackEvent): Boolean; 
var pdata: POneShotCallbackData; 
begin 
    GetMem(pdata, SizeOf(TOneShotCallbackData)); 
    pdata.Callback := Callback; 
    pdata.UserData := UserData; 
    result := (0 <> timeSetEvent(Interval, FResolution, @OneShotCallback, DWord(pdata), TIME_ONESHOT)); 
    if not result then 
    FreeMemory(pdata); 
    end; 
end. 
0

आपको पता है, तो आप एक जीयूआई के लिए, जब तक आप कर के रूप में एक VCL टाइमर का उपयोग करने के लिए है की जरूरत नहीं है कि एक खिड़की हैंडल? आप बस से

fTimer := TTimer.Create(hWindowHandle); 

कोड से एक दृष्टांत सकते हैं और आप

fVirtualWindowHWND := AllocateHWnd(WndMethod); 

को फोन करके एक बना सकते हैं, भले ही आप एक खिड़की संभाल नहीं है, लेकिन उस मामले में आप भी अपने लिखने के लिए है स्वयं का संदेश पाश। मुझे पता है कि विंडोज एपीआई को कॉल करना एक आसान समाधान प्रतीत होता है, लेकिन इसमें अपनी खुद की गुफाएं भी हैं (जैसे आप इसे कक्षा विधि पास नहीं कर सकते ...), और मैंने सोचा, आप शायद इस बारे में जानना चाहें।