Procedure in bestimmten Zeitintervallen ausführen?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Skywalker
Beiträge: 77
Registriert: 22.09.2004 23:35

Beitrag von Skywalker »

Da sind ja schon ein paar nette Beispiele.
Erstmal zum Hintergrund, wofür ich das brauche:

Schreibe mir gerade ein Notify Prog, welche im SysTray liegt und in bestimmten Intervallen nach Mails schaut.
Das Programm tut es auch schon, aber mir fehlt eben noch die Intervall Geschichte.

Ganz grob der Aufbau:

Code: Alles auswählen

Procedure CheckMail()
 .. Verbinde dich mit dem Server
 .. Schaue nach Post
 .. Ist Post da, dann verändere das Icon usw.
EndProcedure

Repeat

 EventID.l = WaitWindowEvent()

 If dies oder das
  dann mache dies oder das
 endif
...
...
until Quit=1
...
...
Ähnlich wie Kaeru Gaman es vorgeschlagen hat, habe ich es auch schon versucht.
Allerdings wird die IF-Abfrage nur dann abgearbeitet, wenn ein Event vorliegt.

Den Timer aus den PureTools habe ich eben auch mal ausprobiert.
Allerdings stoppt dann meine CheckMail() Prozedure das ganze Windows enorm.
Nun dachte ich mir, den Timer gleich zu beginn meiner CheckMail() Prozedure erstmal zu stoppen, aber das funktioniert natürlich auch nicht.
Also ungefähr so:

Code: Alles auswählen

...
...
Procedure CheckMail()
  EndTimer(0)
 .. Verbinde dich mit dem Server
 .. Schaue nach Post
 .. Ist Post da, dann verändere das Icon usw.
EndProcedure

StartTimer( 0, 30000, @CheckMail() )
Repeat

 EventID.l = WaitWindowEvent()

 If dies oder das
  dann mache dies oder das
 endif
...
...
until Quit=1
...
...
Da muß ich wohl noch was weiterforschen
Gruß
Thomas
Benutzeravatar
freedimension
Admin
Beiträge: 1987
Registriert: 08.09.2004 13:19
Wohnort: Ludwigsburg
Kontaktdaten:

Beitrag von freedimension »

Vielleicht helfen dir da "Multimedia Timer". Einfach mal im PSDK danach suchen.
timeSetEvent
The timeSetEvent function starts a specified timer event. The multimedia timer runs in its own thread. After the event is activated, it calls the specified callback function or sets or pulses the specified event object.

MMRESULT timeSetEvent(
UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
DWORD_PTR dwUser,
UINT fuEvent
);
Parameters
uDelay
Event delay, in milliseconds. If this value is not in the range of the minimum and maximum event delays supported by the timer, the function returns an error.
uResolution
Resolution of the timer event, in milliseconds. The resolution increases with smaller values; a resolution of 0 indicates periodic events should occur with the greatest possible accuracy. To reduce system overhead, however, you should use the maximum value appropriate for your application.
lpTimeProc
Pointer to a callback function that is called once upon expiration of a single event or periodically upon expiration of periodic events. If fuEvent specifies the TIME_CALLBACK_EVENT_SET or TIME_CALLBACK_EVENT_PULSE flag, then the lpTimeProc parameter is interpreted as a handle to an event object. The event will be set or pulsed upon completion of a single event or periodically upon completion of periodic events. For any other value of fuEvent, the lpTimeProc parameter is interpreted as a function pointer with the following signature: void (CALLBACK)(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);

dwUser
User-supplied callback data.
fuEvent
Timer event type. This parameter may include one of the following values. Value Meaning
TIME_ONESHOT Event occurs once, after uDelay milliseconds.
TIME_PERIODIC Event occurs every uDelay milliseconds.


The fuEvent parameter may also include one of the following values. Value Meaning
TIME_CALLBACK_FUNCTION When the timer expires, Windows calls the function pointed to by the lpTimeProc parameter. This is the default.
TIME_CALLBACK_EVENT_SET When the timer expires, Windows calls the SetEvent function to set the event pointed to by the lpTimeProc parameter. The dwUser parameter is ignored.
TIME_CALLBACK_EVENT_PULSE When the timer expires, Windows calls the PulseEvent function to pulse the event pointed to by the lpTimeProc parameter. The dwUser parameter is ignored.
TIME_KILL_SYNCHRONOUS Passing this flag prevents an event from occurring after the timeKillEvent() function is called.



Return Values
Returns an identifier for the timer event if successful or an error otherwise. This function returns NULL if it fails and the timer event was not created. (This identifier is also passed to the callback function.)

Remarks
Each call to timeSetEvent for periodic timer events requires a corresponding call to the timeKillEvent function.

Creating an event with the TIME_KILL_SYNCHRONOUS and the TIME_CALLBACK_FUNCTION flag prevents the event from occurring after the timeKillEvent function is called.
Beginne jeden Tag als ob es Absicht wäre!
Bild
BILDblog
Benutzeravatar
hardfalcon
Beiträge: 3447
Registriert: 29.08.2004 20:46

Beitrag von hardfalcon »

Und weshalb nimmst du nicht meinen Vorschlag (oder gehst zumindest darauf ein)? *beleidigt*
Du könntest ja z.B. die Eventabfrage oder eben den "getimten Procedureaufruf" als Thread starten, wobei du beide Threads über eine globale Variable "kommunizieren" lassen könntest. Sprich, die Mail-Procedure setzt die Variable z.B. auf 1, wenn Post da ist, und auf 0, wenn nix neues da ist. Die Hauptschleife, in der das Evenloop inegriert ist, fragt dann dauernd diese globale Variable ab.
Team100
Beiträge: 104
Registriert: 13.09.2004 22:59

Beitrag von Team100 »

Ich verwende seit längerem die folgende Timerprozedur mit gutem
Erfolg. Ich habe sie ein wenig als Demo zusammengefaßt.

Folgende Anforderungen waren gestellt:

- Einfügen in einen normalen Programmcode soll möglich sein
(wenn auch mit Umstellung von WaitWindowEvent auf WindowEvent)

- Mehrere Timerfunktionen sollen möglich sein

- threadlose Lösung ( ....wegen schlechtem Gefühl bei Threads,
eventuell ja unbegründet)

- Rücksetzung des Timers soll möglich sein

- Laufzeit auch über 13 Tage hinaus (wenn EllapsedMilliseconds
kollabiert). Manche schalten ihren PC ja nie aus.....

Code: Alles auswählen

;22_02_2005 by  *** Team100 ***                    tested WinXP 
;Universal Timer using milliseconds of the day as reference
;Easy to reset the timer by setting individual lasttime() flag to zero
;thread-less solution for timer events

Enumeration
  #Window_0
EndEnumeration

Enumeration
  #ScrollBar_0
  #Button_0
  #Radio_0
  #Radio_1
  #Text_0
  #Button_1
  #CheckBox_0
  #CheckBox_1
EndEnumeration

Global FontID1
FontID1 = LoadFont(1, "Arial", 14)
Global FontID2
FontID2 = LoadFont(2, "Arial", 22)
Global FontID3
FontID3 = LoadFont(3, "Arial", 28)

Dim lasttime(100) ; argument: highest enumeration of gadgets

Procedure Open_Window_0()
  If OpenWindow(#Window_0, 349, 133, 153, 285,  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar , "Timer Test")
    If CreateGadgetList(WindowID())
      ScrollBarGadget(#ScrollBar_0, 30, 50, 90, 30, 0, 1, 0)
      ButtonGadget(#Button_0, 30, 230, 90, 40, "Press here", #PB_Button_Default)
      OptionGadget(#Radio_0, 90, 180, 20, 30, "")
      OptionGadget(#Radio_1, 40, 180, 20, 30, "")
      TextGadget(#Text_0, 60, 130, 30, 40, "A")
      SetGadgetFont(#Text_0, FontID3)
      ButtonGadget(#Button_1, 50, 100, 50, 20, "", #PB_Button_Default | #PB_Button_Toggle)
      CheckBoxGadget(#CheckBox_0, 50, 10, 30, 20, "")
      CheckBoxGadget(#CheckBox_1, 90, 10, 20, 20, "")
    EndIf
 EndIf
EndProcedure

Procedure time_in_millisekunden()
 GetSystemTime_ (system.SYSTEMTIME)
 zeitinmillisekunden.l = system\wmilliseconds + (system\wsecond * 1000) + (system\wminute * 60 * 1000) + (system\whour * 1000 * 3600)
ProcedureReturn = zeitinmillisekunden
EndProcedure

Procedure event_timer(number, looptime, time_to_wait)  ; use this procedure for multiple timer needs
 If looptime - lasttime(number) > time_to_wait
    lasttime(number) = looptime
    ProcedureReturn = #True
 ElseIf looptime < lasttime(number) ; for changing values at 12pm
    lasttime(number) = looptime
 EndIf
ProcedureReturn = #False
EndProcedure

Procedure event_timer_single(looptime, time_to_wait)  ; use this procedure for a single timer 
Static lasttime
 If looptime - lasttime > time_to_wait
    lasttime = looptime
    ProcedureReturn = #True
 ElseIf looptime < lasttime  ; for changing values at 12pm
    lasttime = looptime
 EndIf
ProcedureReturn = #False
EndProcedure

;######### Main #####################

Open_Window_0()

Repeat
  looptime = time_in_millisekunden()  ; should be placed here for correct timer reset

  Event = WindowEvent()  ; not WaitWindowEvent
  
  If Event = #PB_EventGadget
     GadgetID = EventGadgetID()
    If GadgetID = #Button_0
      SetGadgetText(#Text_0, "#")
      lasttime(#Text_0) = looptime   ; reset timer #Text_0 
;   Elseif ...... your other events    
    
    EndIf
  EndIf

;######## Timer events now: ###########################

If event_timer(#Text_0, looptime, 2000) = #True  ; time in milliseconds
   toggle_1!1
   SetGadgetText(#Text_0, Str(toggle_1))
EndIf 

If event_timer(#Radio_0, looptime, 333) = #True
   toggle_2!1
   SetGadgetState(#Radio_0, toggle_2)
   SetGadgetState(#Radio_1, toggle_2!1)
EndIf 

If event_timer(#Button_1, looptime, 500) = #True
   toggle_3!1
   SetGadgetState(#Button_1, toggle_3)
EndIf 

If event_timer(#CheckBox_0, looptime, 150) = #True
   toggle_4!1
   SetGadgetState(#CheckBox_0, toggle_4)
EndIf 

If event_timer(#CheckBox_1, looptime, 160) = #True
   toggle_5!1
   SetGadgetState(#CheckBox_1, toggle_5)
EndIf 

If event_timer(#ScrollBar_0, looptime, 1000) = #True
   toggle_6!1
SetGadgetState(#ScrollBar_0, toggle_6)
EndIf 

Delay(10)  ; don't forget
  
Until Event = #PB_EventCloseWindow

End
Eventuell könnte man ja noch was verbessern ?

@Skywalker

vielleicht hilfts ja weiter. Du würdest bei nur einer benötigten
Timerfunktion mit der vereinfachten Procedure (event_timer_single)
weiterkommen.

Cu von Team100
Kompliziert kann es jeder lösen, aber das wirklich Geniale ist einfach.....
Benutzeravatar
bluejoke
Beiträge: 1244
Registriert: 08.09.2004 16:33
Kontaktdaten:

Beitrag von bluejoke »

Was spricht eigentlich gegen einen Thread, der das ElapsedMilliseconds-Teil hernimmt, und im gegebenen Fall einen Event per PostMessage sendet, also so, dass mans in der Hauptschleife mitkriegt?
Ich bin Ausländer - fast überall
Windows XP Pro SP2 - PB 4.00
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

Team100 hat geschrieben:- Laufzeit auch über 13 Tage hinaus (wenn EllapsedMilliseconds
kollabiert). Manche schalten ihren PC ja nie aus.....
ACH DU HEIMATLAND!

Daran hab ich ja noch überhaupt nicht gedacht...

also, wenn ein game bei der Ausführung zufällig über die zurücksetzung
von EllapsedMilliseconds drüberfährt, dann bleibt es stecken?
(weil es ja 13 Tage wartet...?)
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Team100
Beiträge: 104
Registriert: 13.09.2004 22:59

Beitrag von Team100 »

@bluejoke

Ich habe noch nicht viel mit Threads rumprobiert, habe aber immer
wieder Meldungen in den Foren gefunden, daß Leute Probleme auch bei
Nichtvorhandensein von Strings haben, z.B. hier
http://forums.purebasic.com/english/vie ... hp?t=13712

darüberhinaus scheint Threadsicherheit einigen Aufwand zu erfordern
http://forums.purebasic.com/english/vie ... php?t=9624

Da meine Programme absolut zuverlässig laufen müssen (bei Kunden)
habe ich auf Threads vorerst mal verzichtet. Es fehlt mir einfach die
Erfahrung, Threads wirklich sicher zu gestalten. Daß man nichteinmal
mit Debug was auslesen kann (dann hat man ja schon einen String
im Thread) macht auch nicht so wirklich Spass. :|

ElapsedMilliseconds hat wiederum den Nachteil, daß es nach 13 Tagen
eingeschaltener PC kollabiert, d.h. die Grenze der Longs ist erreicht und
es wird mit - zurückgezählt. Ich werde mich hüten Software mit
ElapsedMilliseconds auf unbekannten PCs zu installieren, die möglicherweise in der Nacht
nicht ausgeschaltet werden. Zu Hause ist das natürlich was anderes.

Cu von Team100
Zuletzt geändert von Team100 am 22.02.2005 20:17, insgesamt 1-mal geändert.
Kompliziert kann es jeder lösen, aber das wirklich Geniale ist einfach.....
Benutzeravatar
bluejoke
Beiträge: 1244
Registriert: 08.09.2004 16:33
Kontaktdaten:

Beitrag von bluejoke »

Oh, sorry dass das so rüberkam, als sei meine Antwort auf deinen Post bezogen.
Das war eigentlich nur als neuer Vorschlag gedacht, und nicht irgendwie als Verbesserung, oder so, deiner Lösung.
Ich versteh deine Gründe natürlich voll und ganz.
Ich bin Ausländer - fast überall
Windows XP Pro SP2 - PB 4.00
Team100
Beiträge: 104
Registriert: 13.09.2004 22:59

Beitrag von Team100 »

@kaeru

Kommt drauf an: Wenn ElapsedMilliseconds den Wert 2147483647
erreicht dann springt es auf -2147483648 um und zählt rückwärts, d.h
addiert jede Sekunde 1 dazu. Das geht so bis Null erreicht ist
und dann wieder normal weiter. Wenn dein Programm auf die Möglichkeit
negativer Werte von ElapsedMilliseconds Rücksicht nimmt hast Du
keine Probleme .... :mrgreen:

@bluejoke

Habs auch nicht so aufgefaßt. Alles Ok. Das Thema ist einfach und doch
sehr komplex....

@all

Sorry, hab mich verlesen in meinen Unterlagen: Es sind nicht 13 Tage
sondern genau 24 Tage und 20 Stunden.


Cu von Team100
Zuletzt geändert von Team100 am 22.02.2005 20:26, insgesamt 1-mal geändert.
Kompliziert kann es jeder lösen, aber das wirklich Geniale ist einfach.....
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> Wenn dein Programm auf die Möglichkeit negativer Werte von ElapsedMilliseconds Rücksicht nimmt hast Du keine Probleme ....

prima, das lässt sich ja einbauen, dann evtl. ruckelts nur kurz...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten