Callback Funktionen

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    Unsere Datenschutzerklärung wurde aktualisiert. Mit der Nutzung unseres Forums akzeptierst Du unsere Datenschutzerklärung. Du bestätigst zudem, dass Du mindestens 16 Jahre alt bist.

    • Callback Funktionen

      Hallo,
      Ich beschäftige mich gerade mit Callback-Funktionen.
      Dabei ist mir eine Idee für XProfan gekommen.
      Gerade bei den XProfan-Funktionen, die Listen bearbeiten,
      wäre es doch hilfreich, so einen Callback unterzuschieben.
      Ich denke da vor allem an die MOVE - Funktionen. Die
      arbeiten ja rekursiv, um halt die Listenelemente hin- und
      her zu schieben.

      Wenn man jetzt eine PROC schreiben könnte, die bei der
      Move-Funktion VOR jedem einzelnen Schieben eines Elementes
      aufgerufen wird, den zu schiebenden Eintrag noch bearbeitet
      oder überprüft etc. und dann halt -1 oder 1 zurück gibt.
      Bei -1 überspringt die Move-Funktion diesen Eintrag und bei
      1 wird wie üblich verfahren. Natürlich müßte Roland dann
      auch einen Listboxliste - Index (&ListboxItem) als Systemvariable
      bereitstellen. Dieser Index kann man dann nutzen, um z.B. in
      einem Array, Gridbox, Listbox usw. den entsprechenden Eintrag
      heraus zu ziehen. Dieser ist ja identisch mit der aktuellen Position
      in der Listboxliste. Roland müßte den dann nach jedem Schieben
      und auch Überspringen (Rückgabe -1) um 1 erhöhen.
      Sowas ginge ja dann auch in beiden Richtungen :
      Move("ListToHandle",..) und Move("HandleToList",...)

      Das könnte dann vielleicht so aussehen :

      Quellcode

      1. SET("CallBack", "Movefunktion", "CALLBACK-PROC")
      2. oder evtl auch :
      3. SET("Callback", "Container", "Containerfunktion", "CALLBACK-PROC")
      4. Die PROC dazu :
      5. PROC CALLBACK-PROC
      6. Parameters Long index
      7. ....
      8. RETURN -1 | 1
      9. ENDPROC
      Alles anzeigen
      Da bräuchte die CALLBACK-PROC noch nicht einmal Parameter oder nur einen
      einzigen, der den index des gerade abzuarbeitenden Eintrag angibt (s.o.).
      Dann bräuchte man auch keine extra Systemvariable.


      Anwendungsmöglichkeiten sehe ich da viele. Man kann z.B. unrelevante Einträge einer
      Liste im vorraus ausfiltern, etwa noch ein Datum dem Listeneintrag voranstellen, vlt.
      mit Spalten einer Gridbox (spalte1 * spalte2) mit val() umwandeln und rechnen usw.
      Oder man wirft Einträge der Gridbox, die in der ersten Spalten mit einem "*" als gelöscht
      markiert sind, in der CallbackProc heraus und hat dann nur noch die relevanten Daten.

      Auf jeden Fall würde man sich eine Schleife und noch eine extra Liste sparen. Wenn ich
      alles in allem rechne, dürfte auch die Geschwindigkeit unkritisch sein. Es dürfte sogar
      etwas schneller gehen, da man sich eine WhileLoop - Schleife erspart.

      Eure Meinungen dazu würden mich mal interessieren.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von H.Brill ()

    • Aus der Hilfe von XProfan-11:

      Brainfuck-Quellcode

      1. '28.10 - CallBack-Funktionen
      2. '--------------------------------------------------------------------------------
      3. 'Benötigt wird dazu die neue Funktion @ProcAddr, die als ersten Parameter den Namen der Prozedur hat
      4. 'und als zweiten die Anzahl der Parameter. CallBack-Funktionen werden oft benötigt, wenn es z.B. um
      5. 'Aufzählungen geht. Hier ein Beispiel, das mittels der Windows-API die installierten Fonts ermittelt:
      6. '-Begin-----------------------------------------------------------------
      7. $H Windows.ph
      8. '-CallBack Prozedur---------------------------------------------------
      9. Proc FontListe
      10. Parameters LogFont&, TextMetric&, FontType&, Data&
      11. Declare Font$
      12. Font$ = String$(LogFont&,60)
      13. If Font$ > ""
      14. Addstring Font$
      15. Return 1
      16. Else
      17. Return 0
      18. EndIf
      19. EndProc
      20. '---------------------------------------------------------------------
      21. Cls
      22. ClearList
      23. ~EnumFontFamilies(%hDC, 0, @ProcAddr("Fontliste", 4), 0)
      24. Decimals 0
      25. Print @Str$(%GetCount + 1) + " Fonts gefunden"
      26. Listbox$("Installierte Fonts",1)
      27. '-End-------------------------------------------------------------------
      28. End
      Alles anzeigen
      Welche Wünsche sind da offen? Nur Voraus-Filtern? AddString könnte ja mit IF match$() verknüpft werden... Oder geht es um Geschwindigkeit?

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von p. specht ()

    • ~EnumFontFamilies erwartet ja schon einen Callback, die Move-Funktionen aber nicht.

      Es ging mir vor allem darum, daß die Quell-Liste (entweder Handle oder Listboxliste)
      original erhalten bleibt. Da Roland bei den Move-Funktionen sowieso durch die Quell-
      liste iteriert, wäre es doch logisch, wenn man dort eine Proc dazwischen schalten könnte.

      Oder stell dir vor, du hättest den Inhalt einer Datenbank in einer Gridbox. Bei den nicht
      gebrauchten Datensätzen setzt der Anwender während des Programmlaufes eine
      Löschkennzeichnung. Nun sollen die noch gültigen DS in eine andere Liste geschoben
      werden, um sie z.B. von anderen Programmteilen weiter bearbeiten zu lassen oder
      auch um gespeichert zu werden. Da nützt dir eine Move-Funktion nichts mehr. Da mußt
      du schon eine neue leere Liste erstellen und dann mit AddString in einer Schleife filtern.

      Könnte man nun einer Move-Funktion eine Callback-Proc unterschieben, die dann filtert
      und je nachdem -1 oder 1 zurück gibt. Die Move-Funktion ruft dann bei jedem Listeneintrag
      die Callback-Proc auf, erkennt anhand der Rückgabe, ob sie den aktuellen zu Eintrag
      verschieben kann oder ob sie den Eintrag überspringt.

      Quellcode

      1. PROC Filterproc
      2. Parameters Long index
      3. If GeText$(Gridbox, index, 0) = "*" ' z.B. 1.Spalte
      4. Return -1
      5. Else
      6. Return 1
      7. EndIf
      8. ENDPROC
      Wobei index von der Move-Funktion geliefert wird. Er gibt den aktuellen zu bearbeitenden
      Zeilenindex des zu verschiebenden Listeneintrages an.
      Wäre doch super einfach oder nicht ?

      Somit bräuchte man nur die Filterproc und die extra Schleife und extra Liste könnten
      entfallen. Das hätte natürlich auch den Effekt, einiges schneller zu sein, als wenn man
      eine extra Schleife vor die Move-Funktion vorschalten muß.

      Vielleicht kommen meine Gedankengänge so besser rüber.

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von H.Brill ()

    • Sicher, kann man das, was ich will, auch selber nachprogrammieren :

      Quellcode

      1. Declare Handle lb, btn1, Long ende
      2. ende = 0
      3. Window 600, 400
      4. lb = Create("Listbox", %HWnd, 0, 10, 10, 150, 100)
      5. btn1 = Create("Button", %HWnd, "Move", 200, 10, 60, 25)
      6. Fillbox()
      7. WhileNot ende
      8. WaitInput
      9. If CliCked(btn1)
      10. Move("HandleToListEx", lb)
      11. Listbox$("Ergebnis", 2)
      12. EndIf
      13. Case %Key = 2 : ende = 1
      14. EndWhile
      15. End
      16. SUBPROC Move.HandleToListEx
      17. Parameters Handle liste
      18. DECLARE STRING zeile, Long x
      19. CLEARLIST 0
      20. WHILELOOP 0, GETCOUNT(liste) - 1
      21. x = CallbackProc(&LOOP)
      22. If x = 1
      23. AddString(0, GETSTRING$(liste, &LOOP))
      24. ElseIf x = 0
      25. Break
      26. EndIf
      27. ENDWHILE
      28. ENDPROC
      29. PROC CallbackProc
      30. Parameters Long index
      31. If Instr("*", GetString$(liste, index)) > 0
      32. Return -1
      33. ElseIf Instr("#", GetString$(liste, index)) > 0
      34. Return 0
      35. Else
      36. Return 1
      37. EndIf
      38. EndProc
      39. Proc Fillbox
      40. AddString(lb, "1. Test - Zeile")
      41. AddString(lb, "*2. Test - Zeile")
      42. AddString(lb, "3. Test - Zeile")
      43. AddString(lb, "*4. Test - Zeile")
      44. AddString(lb, "5. Test - Zeile")
      45. AddString(lb, "*6. Test - Zeile")
      46. AddString(lb, "7. Test - Zeile")
      47. AddString(lb, "*8. Test - Zeile")
      48. AddString(lb, "9. Test - Zeile")
      49. AddString(lb, "#10. Test - Zeile")
      50. EndProc
      Alles anzeigen
      Hier habe ich sogar noch die 0 mit ins Boot genommen. Damit ist es
      möglich, nicht nur zu vergleichen u. evtl. anzuhängen. Man kann sogar
      nur Teile der Liste moven oder bei einer bestimmten Bedingung die
      Move-Funktion abbrechen. Ich glaube, daß man da jede Menge an
      Möglichkeiten hat.

      Aber, wie man sieht, habe ich hier das Rad teilweise neu erfunden.
      Also, warum nicht vorhandene, interne XProfan-Funktionen dafür
      nutzen ? Das wäre schneller und u.U. könnte man noch ASM für
      noch mehr Speed einsetzen.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von H.Brill ()

    • Rein zum Sortieren von Listviews gibts glaub ich eine API, die mit Callbacks arbeitet. Aber eben rein zum Sortieren.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/90TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Mir geht es nicht nur um das Sortieren.
      Da gäbe es eine Menge Möglichkeiten.

      Vielleicht wäre es auch möglich, die Callback-Proc als optionalen
      String-Parameter den Move-Funktionen mitzugeben. Wenn vorhanden,
      wird diese mit eingeklinkt und bei jedem Schleifendurchlauf in der
      Move-Funktion aufgerufen.

      Diese Proc dürfte allerdings nur einen Parameter haben, nämlich
      den Index vom Schleifendurchlauf der Move-Funktion.
      Das 'Protokoll' müßte dann Roland festlegen. Bei Rückgabe
      der Proc von

      1 --> Listeneintrag kopieren, wie gehabt
      -1 --> Index wird übersprungen, also nächster Listeneintrag
      0 --> Move-Funktion wird abgebrochen (damit wäre dann auch ein Teil-Kopieren möglich)

      Mehr bräuchte es dazu eigentlich nicht.
    • ...was ziemlich langsam sein dürfte.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/90TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Die Proc soll ja auch nur eingehängt werden, wenn man sie braucht.
      Ansonsten behaupte ich mal das Gegenteil :
      Es wird schneller.
      Beispiel : Du hast jetzt eine große Liste und willst jetzt irgendwas bei
      jedem Eintrag rausfiltern oder gar einfügen, bevor sie gemoved wird.
      Oder man will auf Plausibiltät der Einträge prüfen oder sonst was.

      Hier mußt du eine extra Schleife bauen, um dies zu erreichen.
      Mit meinem Vorschlag würde die Move-Funktion das on the fly
      gleich mit erledigen. Außerdem gehe ich mal davon aus, daß Rolands
      Schleifen um einiges schneller sind, als die, die wir im Interpreter
      schreiben und in der Runtime laufen lassen.
    • Kommt darauf an wie groß der Aufwand in der Callbackfunktion ist. Grundsätzlich wäre für eine oder andere Callbackfunktion cool.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/90TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Dann rufst Du aber die eingehängte Funktion für jeden Eintrag auf. Dementsprechend wird das Ganze dann doch langsamer. Richtig angestellt dürfte eine eigene "Kopierfunktion" dann auch nicht mehr wesentlich langsamer werden.

      Quellcode

      1. SendMessage(%HWnd, ~wm_SetReDraw, 0, 0)
      2. ' Hier Aktionen ausführen, bis Liste durch
      3. ' While GetCount(Quelle) - 1
      4. ' ...
      5. ' EndWhile
      6. SendMessage (%HWnd, ~wm_SetReDraw, 1, 0)
      7. ~InvalidateRect(%HWnd, 0, 1)
      8. ~UpdateWindow(%HWnd)
      Das Zeitaufwändigste bei AddString und Co ist, daß nach jedem Einfügen in die Liste der Bildschirm aktualisiert wird. Mit obigen Code verhinderst Du das Neuzeichen bei jedem Eintrag und erst wenn alles durch ist, aktivierst Du das Neuzeichen und aktualisiert die Fensteransicht. Sieht im Übrigen auch besser aus, weil in der Liste nichts mehr flackert.

      Gruß Volkmar
    • Noch langsamer wird es auch, wenn ich dafür eine extra Schleife baue
      und diese durchlaufe. Mit dem AddString hast du wohl Recht. Ist aber
      nur für sichtbare Listen relevant. Also bei Move("...toList|toArr",...) usw.
      vernachlässigbar.

      Und der Aufwand in der Callbackproc ist ja nicht all zu groß,

      Quellcode

      1. PROC CallbackProc
      2. Parameters Long index
      3. Return If(Instr("*", GetString$(liste, index)) > 0, -1, 1)
      4. ENDPROC
      wenn man dazu noch das einzeilige IF() benutzt. Hier, um das
      * zu finden.

      Rolands Move-Funktionen selber brauchen ja nur die Proc aufzurufen
      und je nach Rückgabewert (0, 1, -1) entscheiden, ob kopiert oder
      übersprungen wird.


      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von H.Brill ()

    • Aber Du rufst für jeden Schleifendurchlauf der Move-Funktion erst mal eine Funktion auf und die führt für jeden Schleifendurchlauf erst GetString und dann If aus und muß dann auch noch einen Wert zurückliefern. Das dauert auch ;-) Schneller wäre das, wenn nicht der Index sondern der String selbst als Parameter an die Callbackfunktion geliefert würde. Und ich will vielleicht bei meinem Filter überhaupt nicht den String untersuchen sondern nach dem Wert von GetItemData filtern. Dann brauche ich doch wieder den Index :oops: Ein Teufelskreis :-)

      Gruß Volkmar
    • Auf die Schnelligkeit kam es mir in erster Linie gar nicht an.
      Deshalb ja auch als optionaler Parameter zuschaltbar. Wer
      es braucht schaltet die Proc dazu, andernfalls arbeiten die
      Move-Funktionen wie bisher.

      Ob es langsamer wird, sieht man erst, wenn man einige
      tausende von Einträgen hat und im Millisekundenbereich
      messen würde. Für den 'normalen Gebrauch' dürfte das
      kaum ins Gewicht fallen.

      Mir ging es vielmehr darum, die vorhandenen, eingebauten
      Move-Funktionen optimaler nutzen zu können. Mit meinem
      Vorschlag wären die Move-Funktionen viel flexibler.

      Aber warten wir mal ab, ob Roland
      a) es interessant findet, es überhaupt einzubauen
      b) es überhaupt leicht für Roland machbar wäre.
    • H.Brill schrieb:

      Mir ging es vielmehr darum, die vorhandenen, eingebauten Move-Funktionen optimaler nutzen zu können.
      "optimal" ist ein Absolutadjektiv und kann nicht gesteigert werden. :-D
      Aber Mal im Ernst: Der Zeitverlust durch die wiederholte Abarbeitung sollte wirklich nicht unterschätzt werden.
      XProfan-Semiprofi (XProfan X4a+XPIA+LemonEd)
      Ryzen 1700X/MSI B350 PC MATE/16GB RAM@2933MHz/Radeon HD7770 OC/Creative X-Fi XTreme Music/90TB HDD+256GB Samsung 960 EVO/28" Samsung 4k
      XBox Classic/360S/One S/One X Scorpio Edition/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84) auf 60" 4k/3D LG
      OnePlus 7 8GB/256GB
      jacdelad.bplaced.net
    • Ich weiß jetzt wirklich nicht, warum ihr euch an der Zeit bzw.
      Ausführungs-Geschwindigkeit aufhängt ? Ich denke, ihr verliert
      da was aus den Augen.

      XProfan ist halt nun einmal ein Bytecode-Interpreter bzw. Bytecode-
      Compiler.

      Wollt ihr mir denn glaubhaft machen, daß XProfan-Bytecode schneller
      ist, als Delphi-Code ? Da liegt immerhin noch eine Schicht dazwischen.
      Entweder ist es die Profan.exe als Interpreter oder Profrun32.exe, die
      den Bytecode in der .exe ausführt.

      Was ist denn schneller ?
      MeineFunktion() aus meiner Schleife aufgerufen oder MeineFunktion()
      von Roland in seinem Delphi-Code in dessen Schleife aufgerufen ?

      Ich glaube doch eher der Delphi-Code !!!!!!