Seite 1 von 2

XY-Schreibermodul mit Scrollfunktion

Verfasst: 28.03.2007 12:04
von legion
PureBasic 4.02
XY-Schreibermodul mit Scrollfunktion und Datenspeicherfunktion
Die Aufzeichnungsdauer ist durch das "XYArray.l(999999)" begrenzt
Die Aktualisierungsrate kann im Thread durch "Delay" eingestellt werden
Nach dem Laden einer Datendatei setzt der Schreiber an der zuletzt gespeicherten Position fort
Herzlichen Dank an das Forum für eure Unterstützung ! ! ! ! ! ! ! !
Änderungen am Code die eine Verbesserung darstellen sind erwünscht !

Lg. Legion

Update !
Auf Grund eurer Fehlerbeschreibung hab ich folgende Änderungen vorgenommen:

Während der Schreiberthread läuft hab ich die "CallBackFunktion" abgeschaltet.
Die Abfrage der Startposition vereinfacht.
Es können nur noch spezifische (*.dat) Files geöffnet werden.

Ich hoffe das Prog. läuft jetzt fehlerfrei !

Code: Alles auswählen

Enumeration
  #Window_0
EndEnumeration

Enumeration
  #TrackBar_0
  #ScrollBar_0
  #Text_0
  #Button_0
  #Button_1
  #Button_2
  #Button_3
  #Button_4
EndEnumeration
;------------------------------------------------------------------------------------------------------ 
Global X = 0
Global Y = 218
Global Dim XYArray.l(999999)
Global Startpos.l   = 0
Global ScrollPos.l
Global ExitThread.b = 1
Declare WindowCallback(hWnd.l,uMsg.l,wParam.l,lParam.l)
;------------------------------------------------------------------------------------------------------ 
Procedure Open_Window_0()
  If OpenWindow(#Window_0, 216, 0, 664, 600, "XY-Schreiber",  #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar )
    If CreateGadgetList(WindowID(#Window_0))
      OpenWindowedScreen(WindowID(#Window_0),20,20,620,435,0,0,0)
      TrackBarGadget(#TrackBar_0, 20, 500, 620, 30, 0, 435)
      SetGadgetState(#TrackBar_0,218)
      ScrollBarGadget(#ScrollBar_0, 20, 460, 620, 20, 0, 620, 620)
      HideGadget(#ScrollBar_0, 1)
      TextGadget(#Text_0, 290, 485, 200, 15, "Bewege mich ! ! ! ! ")
      ButtonGadget(#Button_0,30,550, 100, 30, "Start")
      ButtonGadget(#Button_1,150,550, 100, 30, "Stop")
      ButtonGadget(#Button_2,270,550, 100, 30, "Speichern")
      ButtonGadget(#Button_3,390,550, 100, 30, "Laden")
      ButtonGadget(#Button_4,520,550, 100, 30, "Beenden")          
    EndIf
  EndIf
EndProcedure
;------------------------------------------------------------------------------------------------------ 
Procedure Schreiber(DelayTime)
Protected i
SetWindowCallback(0) 
Repeat
 ClearScreen($0)
 StartDrawing(ScreenOutput())
 FrontColor($80C020)
 DrawingMode(1)
 XYArray(X)= GetGadgetState(#TrackBar_0)
 If X > 620  
  Startpos = Startpos +1
  SetGadgetAttribute(#ScrollBar_0, #PB_ScrollBar_Maximum, GetGadgetAttribute(#ScrollBar_0, #PB_ScrollBar_Maximum)+1)
  SetGadgetState(#ScrollBar_0, 620 + X)
 EndIf
 For i = Startpos +1 To X
  LineXY(i-Startpos,XYArray(i-1),i-Startpos,XYArray(i),$67FDB0)
 Next i
 StopDrawing()
 FlipBuffers()
 X = X + 1
 Delay(DelayTime)
Until ExitThread
SetWindowCallback(@WindowCallback())
EndProcedure
;------------------------------------------------------------------------------------------------------ 
Procedure ScrollPicture()
Protected i
 ClearScreen($0)
 StartDrawing(ScreenOutput())
 FrontColor($80C020)
 DrawingMode(1)
 For i = 0 To 618
  LineXY(i,XYArray(i+ScrollPos),i+1,XYArray(ScrollPos+i+1),$67FDB0)
 Next i
 StopDrawing()
 FlipBuffers()
EndProcedure
;------------------------------------------------------------------------------------------------------ 
Procedure SaveTofile()
Protected i
Protected Pattern$ = "DAT (*.dat)|*.dat"
If X > 2
 DateiName$ = SaveFileRequester("Datei speichern unter ...","C:\Schreiber.dat", Pattern$, PatternPosition)
 If CreateFile(0,DateiName$)
  WriteString(0,"PureBasic XY-Schreiber File")
  For i = 0 To X
   WriteLong(0,i) : WriteLong(0,XYArray(i))
  Next i
  CloseFile(0)
 EndIf
Else
 MessageRequester("Fehler", "Keine Daten zum Speichern !", #MB_OK|#MB_ICONWARNING)
EndIf 
EndProcedure
;------------------------------------------------------------------------------------------------------ 
Procedure LoadFromFile()
Protected u
Protected Pattern$ = "DAT (*.dat)|*.dat"
Protected Dateikennung$
HideGadget(#ScrollBar_0, 1)
SetGadgetAttribute(#ScrollBar_0, #PB_ScrollBar_Maximum,620)
DateiName$ = OpenFileRequester("Datei öffen ...","C:\Schreiber.dat", Pattern$, Pattern)
If DateiName$
 If OpenFile(0, DateiName$)
 Dateikennung$ = ReadString(0)
 If Dateikennung$ <> "PureBasic XY-Schreiber File"
  MessageRequester("Fehler", "Keine gültige Schreiberdatei !", #MB_OK|#MB_ICONWARNING)
  Goto home
 EndIf
  Startpos = 0 : u = 0 : ScrollPos = 0 : Dim XYArray.l(999999)
  FileSeek(0, 27)
  While Eof(0) = 0
   u = ReadLong(0) : XYArray(u) = ReadLong(0)
   If u > 620
    Startpos = Startpos +1
    SetGadgetAttribute(#ScrollBar_0, #PB_ScrollBar_Maximum, GetGadgetAttribute(#ScrollBar_0, #PB_ScrollBar_Maximum)+1)
    SetGadgetState(#ScrollBar_0, 0)
   EndIf
  Wend
  CloseFile(0)
 EndIf
 X = u
 If X > 620 : HideGadget(#ScrollBar_0, 0) : EndIf
 SetGadgetState(#TrackBar_0, XYArray(X-1))
 ScrollPicture()
EndIf
home:
EndProcedure
;------------------------------------------------------------------------------------------------------ 
Procedure WindowCallback(hWnd.l,uMsg.l,wParam.l,lParam.l)
   If uMsg = #WM_HSCROLL And lParam = GadgetID(#ScrollBar_0)
      ScrollPos = GetGadgetState(#ScrollBar_0)
      If ExitThread = 1 : ScrollPicture() : EndIf
   EndIf 
   ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure 
;------------------------------------------------------------------------------------------------------ 
Procedure StartSchreiber()
If ExitThread = 1
 SchreiberThread = CreateThread(@Schreiber(),10)
 HideGadget(#ScrollBar_0, 1)
EndIf
EndProcedure
;------------------------------------------------------------------------------------------------------ 
InitSprite()
InitKeyboard()
Open_Window_0()
SetWindowCallback(@WindowCallback())
;------------------------------------------------------------------------------------------------------  
Repeat
 If ExitThread = 0
  DisableGadget(#Button_2,1) : DisableGadget(#Button_3,1) : DisableGadget(#Button_4,1)
 Else 
  DisableGadget(#Button_2,0) : DisableGadget(#Button_3,0) : DisableGadget(#Button_4,0)
 EndIf
;------------------------------------------------------------------------------------------------------ 
 Event = WaitWindowEvent()  
 WindowID = EventWindow()  
 GadgetID = EventGadget() 
 EventType = EventType()   
 If Event = #PB_Event_Gadget
  If GadgetID = #TrackBar_0    
  ElseIf GadgetID = #ScrollBar_0
  ElseIf GadgetID = #Button_0 : StartSchreiber() : ExitThread = 0
  ElseIf GadgetID = #Button_1 : ExitThread = 1 : If X > 620 : HideGadget(#ScrollBar_0, 0) : EndIf
  ElseIf GadgetID = #Button_2 : ExitThread = 1 : SaveTofile()
  ElseIf GadgetID = #Button_3 : ExitThread = 1 : LoadFromFile()
  ElseIf GadgetID = #Button_4 : ExitThread = 1 : Break
  EndIf    
 EndIf  
Until Event = #PB_Event_CloseWindow
End
;------------------------------------------------------------------------------------------------------ 

Verfasst: 28.03.2007 13:46
von AND51
Geiles Teil! Gute Arbeit! Hab erstmal den Herzschlag nachgestellt: Beep! Beep! Beeeeeeeeeeeeep! :lol:

Verbeserung erwünscht:
> Die Aufzeichnungsdauer ist durch das "XYArray.l(999999)" begrenzt
Warum nimmste keine LinkedList? Spart Speicher, weil nur benötigte Felder belegt werden und nicht 999999 Felder auf einen Schlag definiert werden, außerdem ist die Anzahl der Felder in einer LinkedList unbegrenzt.

Verfasst: 28.03.2007 16:52
von Kaeru Gaman
AND51 hat geschrieben:Warum nimmste keine LinkedList? Spart Speicher, ...
LOL...?

aber nur solange er wesentlich weniger elemente hat....

in den speicher eines Long-Arrays mit 999999 elementen passt eine LL mit 333333 elementen.
ein einfaches Long-element braucht 3x soviel platz, weil es eben noch zwei pointer beinhaltet.

eine passable lösung wäre, ReDim zu benutzen, und den platz 1000-elemente-weise zu reservieren.

also, er läßt nen zähler mitlaufen, und immer wenn 1000 elemente voll sind, redimt er +1000 weitere.

Verfasst: 28.03.2007 17:45
von THEEX
Stopt man das Ganze und startet es danach wieder, stürzt es ab. Aber erst, wenn es gescrollt ist.

Verfasst: 28.03.2007 18:28
von AND51
Ja und Kaeru? Man kann nie wissen, ob der Programmierer mehr als 333333 Elemente braucht, was wenn nicht? Dann ist es "rausgeworfenes Gel... äh... Speicher".

Es kommt natürlich auf die Messungen an, messe ich in kurzem Interval (=viele Daten), dann ist sicherlich ein Array praktischer.
Messe ich in längeren Intervallen, oder in so einer Art, dass nur wenige Daten zusammen kommen, wäre eine LinkedList evtl. angemessen.

Aber dein Vorschlag mit dem "dynamischen Array" klingt auch nicht schlecht.

Ich arbeite lieber LinkedLists anstatt mit Arrays, daher ist es für mich interessant zu wissen, wieso eine LinkedList doppelt so viele Pointer braucht, kannst du mir das vielleicht in einer PN erklären?

Verfasst: 28.03.2007 18:52
von Kaeru Gaman
muss keine PN sein.

in einem array folgen die werte einfach nacheinander, keine internen pointer werden benötigt.

bei einer LL haben die elemente eine reihenfolge, die nicht zwangsweise der reihenfolge im speicher entspricht.
(z.b. nach einem Insert)
deshalb führt jeder element zwei pointer mit: einen aufs previous, einen aufs next element.
jeder element ist also 8byte größer als es in einem array wäre.

Verfasst: 28.03.2007 19:26
von AND51
Ah, jetzt verstehe ich, wieso auf der Seite von Next/Prevous-Element diese Structure steht, die habe ich bisher nie verstanden (und nie gebraucht)...

Danke.

Aber: Wenn ein Array re-dimensioniert wird, dann steht es doch auch nicht immer zwangsweise an einem Stück im Speicher, oder? Zum Beispiel nach einem AllocateMemory(). Oder interpretiere ich das jetzt falsch?

Verfasst: 28.03.2007 19:31
von Kaeru Gaman
meiner auffassung nach findet ein sauberes re-allocate statt beim redim,
also wenn eine vergrößerung aufgrund folgenden belegten speichers nicht möglich ist,
wird komplett neu allociert und die werte kopiert und das alte freigegeben....

das ist jedenfalls meine vermutung und eigentlich der einzige saubere weg...
ein array muss immer hintereinander stehen, eben weil es keine internen pointer besitzt.

Verfasst: 28.03.2007 19:33
von AND51
Stimmt, deshalb gibt ReAllocateMemory() auch immer einen neuen Pointer zurück, wenn der alte Speicher erfolgreich neu angelegt wurde...
Vermute, dass der Befehl genau so arbeitet, wie du es gerade beim ReDim beschrieben hast.

Verfasst: 29.03.2007 23:35
von Helmut
CSprengel hat geschrieben:Stopt man das Ganze und startet es danach wieder, stürzt es ab. Aber erst, wenn es gescrollt ist.
sobald der Bildausschnitt verlassen wird.
Aber sonst cool.
Das mit dem Parallel_Port verbinden und auf min 8 Kanäle aufmotzen, Zeiten einstellbar machen, fertig ist der Logikanalyser....... Naja ein Ansatz ev. :-)