Frage zu AddWindowTimer()

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Frage zu AddWindowTimer()

Beitrag von Daffy0815 »

@TheCube & ts-soft

Leider zu früh gefreut!

Die Sache funktioniert offenbar nicht in einer Prozedur zwischen While und Wend.
Da ändert sich der Timer rein gar nicht.

Hier ein Beispiel:

Code: Alles auswählen

Enumeration
  #Window_0
  #Image1
  #ImageGadget1
EndEnumeration

CreateImage(#Image1,50,20)

Global Flag

Procedure ToggleFlag(hWnd, uMsg, idEvent, time.l)
  StartDrawing(ImageOutput(#Image1))
  DrawText(3,2,Str(Flag),$AAAAAA)
  StopDrawing()
  SetGadgetState(#ImageGadget1,ImageID(#Image1))
  flag+1
EndProcedure

Procedure TestProc()
  While 0 = 0
    Debug Flag
    If Flag >= 5
      Break
    EndIf  
  Wend
EndProcedure  


If OpenWindow(#Window_0, 100, 100, 200, 60, "Testfenster",  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar)
  ImageGadget(#ImageGadget1,20,20,0,0,ImageID(#Image1),#PB_Image_Border)
Else: End : EndIf

SetTimer_(WindowID(#Window_0), 1, 500, @ToggleFlag())

Repeat   
  
  TestProc()  
  
  
Until WaitWindowEvent() = #WM_CLOSE
Gruß Daffy


PS. @ts-soft

Ist die andere Routine in der Lage einen SICHER einen Timer abzubilden (Habe sie im Programm noch nicht getestet)?
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
TheCube
Beiträge: 169
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: Frage zu AddWindowTimer()

Beitrag von TheCube »

Ich hoffe mal, das war nur ein schlechtes Beispiel. (Konzept?)
1. Soo schnell kommt die Debug Ausgabe auch nicht hinterher (->Delay hinter Debugausgabe)
2. Ohne Fenstereventabarbeitung gehts nicht, da musst du vielleicht ts-soft´s Link versuchen

Aber hier eine schlechte Code-Antwort :lol:

Code: Alles auswählen

Enumeration
  #Window_0
  #Image1
  #ImageGadget1
EndEnumeration

CreateImage(#Image1,50,20)

Global Flag

Procedure ToggleFlag(hWnd, uMsg, idEvent, time.l)
  StartDrawing(ImageOutput(#Image1))
  DrawText(3,2,Str(Flag),$AAAAAA)
  StopDrawing()
  SetGadgetState(#ImageGadget1,ImageID(#Image1))
  Flag+1
EndProcedure

Procedure TestProc(*dummy)
  While 0 = 0
    Debug Flag : Delay (50)
    If Flag >= 5
      Break
    EndIf
  Wend
  Debug "Thread beendet"
EndProcedure 

If OpenWindow(#Window_0, 100, 100, 200, 60, "Testfenster",  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar)
  ImageGadget(#ImageGadget1,20,20,0,0,ImageID(#Image1),#PB_Image_Border)
Else: End : EndIf

Thread=CreateThread(@TestProc(),0)
SetTimer_(WindowID(#Window_0), 1, 500, @ToggleFlag())

Repeat   
  
Until WaitWindowEvent() = #WM_CLOSE
BSP
Beiträge: 203
Registriert: 01.02.2009 14:04

Re: Frage zu AddWindowTimer()

Beitrag von BSP »

Hallo Daffy0815

Dein "hochinteressanter Code" funktioniert schon,
er frist nur die ganze Rechenleistung.
Baue mal in Deine Procedure die inzwischen "berühmt berüchtigte"
"While not WindowEvent() : Wend" ein.
Dann läuft alles weiter und Du siehst, was Du da eigentlich machst.
Das läuft auch weiter, während ich mich hier angemeldet habe und dieses hier tippe.
Gruß: BSP

Code: Alles auswählen

Procedure TestProc()
  ;While 0 = 0
  Repeat
    Debug Flag
    If Flag >= 5
      Break
    EndIf 
    While Not WindowEvent():Wend 
  ;Wend
  ForEver
EndProcedure  
PB 5.31 (x86) & (x64) Win10
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Frage zu AddWindowTimer()

Beitrag von Daffy0815 »

@theCube

Das war natürlich nur ein "schlechtes Beispiel" da ich diesmal "Beschwerden" über die Größe der realen Routinen vermeiden wollte.

Mit der Geschwindigkeit der Debug-Ausgabe hat das aber nichts zu tun (sonst würde die While-Wend-Schleife ohne die Debug-Ausgabe ja abgebrochen werden).

Habe zwischenzeitlich mal die andere Lösung mit While-Wend getestet.

Scheint zu funktionieren!

Code: Alles auswählen

Define TimerResolution.TIMECAPS
Global Dim TimerHandles(15)
Global Dim TimerProcedures(15)

Procedure Timer_Init()
  Shared TimerResolution

  If timeGetDevCaps_(@TimerResolution, SizeOf(TIMECAPS)) = #TIMERR_NOERROR
    If timeBeginPeriod_(TimerResolution\wPeriodMin) = #TIMERR_NOERROR
      ProcedureReturn #True
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure

Procedure Timer_End()
  Protected I
  Shared TimerResolution

  timeEndPeriod_(TimerResolution\wPeriodMin)
  For I = 0 To 15
    If TimerHandles(I)
      timeKillEvent_(TimerHandles(I))
    EndIf
  Next
EndProcedure

Procedure Timer_Callback(TimerHandle, Message, TimerID, wParam, lParam)
  If TimerProcedures(TimerID)
    CallFunctionFast(TimerProcedures(TimerID))
  EndIf
EndProcedure

Procedure TimerStart(TimerID, Delay, ProcAddr)
  If TimerID > 15 Or TimerID < 0 : ProcedureReturn #False : EndIf

  If TimerHandles(TimerID)
    timeKillEvent_(TimerHandles(TimerID))
  EndIf

  TimerProcedures(TimerID) = ProcAddr
  TimerHandles(TimerID) = timeSetEvent_(Delay, 0, @Timer_Callback(), TimerID, #TIME_PERIODIC)

  ProcedureReturn TimerHandles(TimerID)
EndProcedure

Procedure TimerStop(TimerID)
  If TimerID > 15 Or TimerID < 0 : ProcedureReturn #False : EndIf

  If TimerHandles(TimerID)
    timeKillEvent_(TimerHandles(TimerID))

    ProcedureReturn #True
  EndIf

  ProcedureReturn #False
EndProcedure

Procedure TimerGetMaxRes()
  Shared TimerResolution
  ProcedureReturn TimerResolution\wPeriodMax
EndProcedure

Procedure TimerGetMinRes()
  Shared TimerResolution
  ProcedureReturn TimerResolution\wPeriodMin
EndProcedure



Procedure mytimer1()
  Shared hoehe
  Debug "Timer 1"
  If hoehe = 1000: hoehe = 100: EndIf
     Beep_(hoehe,100)
     hoehe+100
     
EndProcedure

Procedure mytimer2()
  Beep_(1800,5)
  Debug "Timer 2"
EndProcedure

Procedure mytimer3()
  Beep_(1800,100)
  Debug "Timer 3"
EndProcedure

Procedure mytimer4()
  Beep_(800,100)
  Debug "Timer 4"
EndProcedure

Procedure TestProc()
  While 0=0
  Wend
EndProcedure  


Timer_Init()

hWnd = OpenWindow(0, (GetSystemMetrics_(#SM_CXSCREEN)-200)/2,(GetSystemMetrics_(#SM_CYSCREEN)-277)/2, 400, 360, "High Resolution Timer by Danilo", #PB_Window_SystemMenu|#PB_Window_SizeGadget)

TimerStart(0, 1000, @mytimer1())
TimerStart(1,  200, @mytimer2())
TimerStart(2, 2000, @mytimer3())
TimerStart(3,  600, @mytimer4())

Repeat
  EventID.l=WaitWindowEvent()

  ; IF LeftMouseButton pressed...
  If EventID = #WM_LBUTTONDOWN
    TimerStop(1): TimerStop(2): TimerStop(3)
  EndIf
  
  TestProc()
  
  
  
  ; pressed CloseButton or ALT+F4 ??
  If EventID = #PB_Event_CloseWindow
     Quit = 1
  EndIf
Until Quit = 1

Timer_End()
Hoffe nur, das mich nicht noch weitere Überraschungen erwarten :)

Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Frage zu AddWindowTimer()

Beitrag von Daffy0815 »

@BSP

Mein "hochinteressanter" Code war doch nur das "Worst-Case-Beispiel"!

In Wirklichkeit werden zwischen dem While und Wend jede Menge Dinge ausgeführt (Bargraphen aufgefrischt, Messwerte via RS232 geholt und und und...).
Dies aber eben nur dann, wenn der Timer einen bestimmten Wert überschreitet. Sonst wäre der Timer ja für die Katz denn schließlich soll er ja die Abfragerate reduzieren.

Es ging ja darum festzustellen ob der Timer in der Lage ist eine andere, laufende Prozedur zu unterbrechen.
Und das kann er offensichtlich nicht.

Mein Problem ist sicherlich das, dass ich normalerweise Microcontroller in Assembler programmiere und da ist man halt mit Interrupts und Timern zu "verwöhnt" :)

So sieht das in meinem Basic für DS89C450 aus:

Code: Alles auswählen


Clock 0,0 
Time(0)=0
On Time(0, 0.5)  Gosub IsrTi0
Clock 0,1

Do
Loop


:IsrTi0
? Time(0)
Time(0)=0
RetI








Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
BSP
Beiträge: 203
Registriert: 01.02.2009 14:04

Re: Frage zu AddWindowTimer()

Beitrag von BSP »

@BSP

Mein "hochinteressanter" Code war doch nur das "Worst-Case-Beispiel"!

In Wirklichkeit werden zwischen dem While und Wend jede Menge Dinge ausgeführt.....
Ja, das habe ich so auch vermutet. :)
Gruß:BSP
PB 5.31 (x86) & (x64) Win10
matbal
Beiträge: 261
Registriert: 30.03.2011 20:53

Re: Frage zu AddWindowTimer()

Beitrag von matbal »

@Daffy0815

Wenn ich dich richtig verstehe, willst du nur die Bildschirmausgaben reduzieren. Warum lagerst du dann deine "Arbeistsprozedur" nicht in einen Thread aus. Die Eventschleife wird so nicht mehr aufgehalten. Das heißt, auch das PB-Timerevent kommt an.

SetTimer geht auch. Wenn hWnd = 0, dann gilt er scheinbar für alle Fenster. (zumindest unter XP)

Code: Alles auswählen

EnableExplicit

Enumeration 
   #FormMain
   #FormMain_Text_Ausgabe
   #Timer_1
EndEnumeration

Global ergebnis

Procedure Arbeit(dummy)
   Repeat
      ergebnis + 1
      Delay(1)
   ForEver
EndProcedure

; (1) Wird vom PB-Timer aufgerufen
Procedure Ausgabe()
   Debug "pbTimer"
   SetGadgetText(#FormMain_Text_Ausgabe, Str(ergebnis))
EndProcedure


; (2) Wird von SetTimer aufgerufen
Procedure cbTimer(hWnd, uMsg, wParam, lParam)
   Debug "cbTimer"
   SetGadgetText(#FormMain_Text_Ausgabe, Str(ergebnis))
EndProcedure

Procedure FormMain_Open()
   If OpenWindow(#FormMain, 100, 200, 200, 50, "programm")
      TextGadget(#FormMain_Text_Ausgabe, 10, 10, 80, 25, "Ausgabe")
      
      ; (1) 
      AddWindowTimer(#FormMain, #Timer_1, 500)
      
      ; (2) 
      ;SetTimer_(0, #Timer_1, 500, @cbTimer())
      
   EndIf
   
EndProcedure

FormMain_Open()
CreateThread(@Arbeit(), 0)

While IsWindow(#FormMain) Or IsWindow(2)
   Select WaitWindowEvent()
      Case #PB_Event_CloseWindow
         CloseWindow(EventWindow())
      Case #PB_Event_Timer
         Select EventTimer()
            Case #Timer_1
               Ausgabe()
         EndSelect
   EndSelect
Wend

;(2)
;KillTimer_(0, #Timer_1)
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Frage zu AddWindowTimer()

Beitrag von Daffy0815 »

@ts-soft

Ich habe nun den von Ihnen überarbeiteten Code eingebaut.
Was mir nur etwas Kopfzerbrechen bereitet, ist das mir die verwendeten Datentypen nicht klar sind.
Auch was die Zeiten betrifft ist mir da etwas unklar.
Was sind das für Werte Mikrosekunden, Millisekunden oder was?
Ich vermute mal Millisekunden.
Ich habe nämlich festgestellt, dass wen man den Wert zu klein wählt (z. B. 10) mein Programm mit "ungültigem Speicherzugriff" aussteigt.


Ist alles was nicht bezeichnet ist ".i" ?

Auch die Proceduren haben mal Rückgabewerte und mal keine Rückgabewerte.

Wie sehen da denn die Prototypen aus?

Gruß

Daffy


PS. Also nach stundenlangem Herumprobieren geb ich es auf mit der Routine.
Sie führt auch bei höheren Werten (z. B. 200) in meinem Programm zu sporadischen Abbrüchen mit "ungültigem Speicherzugriff"
Zuletzt geändert von Daffy0815 am 27.02.2012 14:30, insgesamt 4-mal geändert.
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Frage zu AddWindowTimer()

Beitrag von Daffy0815 »

@matbal

Nein, es geht nicht um die Ausgaberate auf dem Bildschirm wenngleich das auch ein "Nebeneffekt" wäre.

Das Problem ist ein Anderes:

Am PC hängt via serieller Schnittstelle ein Subsystem mit einem Microcontroller.
Der Microcontroller leistet die "eigentliche Arbeit".

Der PC mit dem PureBasic-Programm dient lediglich zur Parametrierung und Visualisierung des Ganzen.

Ein Beispiel:

Auf dem PC befindet sich ein Bild in dem Messwerte in numerischer Form und als Bargraphen dargestellt werden.
Der PC sendet in diesem Fall an das Subsystem die Anforderung "AI<Kanalnummer><CR><Prüfsumme>"
Das Subsystem antwortet mit "AI<Kanalnummer>=<Analogwert><CR><Prüfsumme>

Nun wird/werden der/die empfangene(n) Wert(e) dargestellt.

Die Anfragen erzeugen im Subsytem einen Interrupt und wenn die Anfragen zu häufig kommen dann hat das Subsystem keine Zeit mehr die "eigentliche Arbeit" zu verrichten.

Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Benutzeravatar
Daffy0815
Beiträge: 390
Registriert: 15.06.2005 00:44
Wohnort: 65719 Hofheim
Kontaktdaten:

Re: Frage zu AddWindowTimer()

Beitrag von Daffy0815 »

Hallo Leute,

nachdem alle Versuche mit den hier vorgeschlagenen Methoden einen Timer zu programmieren der in meinem Programm keine "Nebenwirkungen" hat gescheitert sind habe ich mal selbst was zusammengebastelt.
Ob das eine optimale Lösung ist weiß ich nicht aber zumindest funktioniert sie überall und ganz ohne Fenster einwandfrei!

Hier das Testprogramm:

Code: Alles auswählen

Global Time.i

Procedure Timer(*Dummy)
    ;
    TimeOld.i = ElapsedMilliseconds()
    If Sign(TimeOld.i) = -1
        TimeOld.i = TimeOld.i + 2147483648
    EndIf
    ;
    Repeat
        TimeNew.i = ElapsedMilliseconds()
        If Sign(TimeNew.i) = -1
            TimeNew.i = TimeNew.i + 2147483648
        EndIf
        ;
        If TimeNew.i <> TimeOld.i
            Time.i = Time.i + (TimeNew.i - TimeOld.i)
            TimeOld.i = TimeNew.i
        EndIf
    ForEver
EndProcedure


Thread=CreateThread(@Timer(), 0)
#TimeOut = 5000 ;Millisekunden

Repeat   
  ;
  Time.i = 0
  While Time.i < #TimeOut
    Debug Time.i
  Wend  
  ;
Until Time.i >= #TimeOut

KillThread(Thread)
End


Gruß

Daffy
Wir sind LINUX
Widerstand ist zwecklos - Sie werden emuliert
Antworten