XY-Schreibermodul mit Scrollfunktion

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
legion
Beiträge: 467
Registriert: 08.10.2006 18:04
Computerausstattung: Intel Core i5-6500 @ 4x 3.6GHz mit Windows 10 Pro, Intel Core-i7 mit Ubuntu 18.04 bionic, x86_64 Linux 4.18.0-16-generic, Microsoft Surface Pro - Windows 10 Pro
Wohnort: Wien
Kontaktdaten:

XY-Schreibermodul mit Scrollfunktion

Beitrag 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
;------------------------------------------------------------------------------------------------------ 
Zuletzt geändert von legion am 30.03.2007 12:32, insgesamt 1-mal geändert.
PB 5.71 LTS Windows 10 Pro & Ubuntu 18.04.2 LTS & Linux Mint 19.3
-----------------------------------------------------
Alles ist, wie man glaubt, dass es ist!
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
THEEX
Beiträge: 804
Registriert: 07.09.2004 03:13

Beitrag von THEEX »

Stopt man das Ganze und startet es danach wieder, stürzt es ab. Aber erst, wenn es gescrollt ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag 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.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag 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.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Helmut
Beiträge: 162
Registriert: 20.09.2004 22:53

Beitrag 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. :-)
Antworten