Callback Funktionen

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!

  • 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 :

    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.

  • Aus der Hilfe von XProfan-11:

    Welche Wünsche sind da offen? Nur Voraus-Filtern? AddString könnte ja mit IF match$() verknüpft werden... Oder geht es um Geschwindigkeit?

    HP255G7:Win10pro2.004,4*AMD Ryzen3200U@2.60GHz,6+2GB-RadeonVega/237GBSSD:intlDVDRW,3xUSB3 ext4TB-HDX,XProfanX3+Xasm/Xpse

    Einmal 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.

    Code
    PROC Filterproc
    Parameters Long index
    If GeText$(Gridbox, index, 0) = "*" ' z.B. 1.Spalte
       Return -1
    Else
       Return 1
    EndIf
    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.

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


    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.

  • 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 5800X/Gigabyte B550m DS3H/32GB RAM@3600MHz/Radeon HD7770 OC/Asus Xonar SE/108TB HDD+512GB Samsung 980 Pro+2TB Crucial SSD/28" Samsung 4k
    TerraMaster F4-421 mit 28TB
    XBox Classic/360S/Series X/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84)
    OnePlus 6 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 5800X/Gigabyte B550m DS3H/32GB RAM@3600MHz/Radeon HD7770 OC/Asus Xonar SE/108TB HDD+512GB Samsung 980 Pro+2TB Crucial SSD/28" Samsung 4k
    TerraMaster F4-421 mit 28TB
    XBox Classic/360S/Series X/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84)
    OnePlus 6 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 5800X/Gigabyte B550m DS3H/32GB RAM@3600MHz/Radeon HD7770 OC/Asus Xonar SE/108TB HDD+512GB Samsung 980 Pro+2TB Crucial SSD/28" Samsung 4k
    TerraMaster F4-421 mit 28TB
    XBox Classic/360S/Series X/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84)
    OnePlus 6 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.


    Code
    SendMessage(%HWnd, ~wm_SetReDraw, 0, 0)
     ' Hier Aktionen ausführen, bis Liste durch
     ' While GetCount(Quelle) - 1
     ' ...
     ' EndWhile
    SendMessage (%HWnd, ~wm_SetReDraw, 1, 0)
    ~InvalidateRect(%HWnd, 0, 1)
    ~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ß,

    Code
    PROC CallbackProc
    Parameters Long index
    Return If(Instr("*", GetString$(liste, index)) > 0, -1, 1)
    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.



  • 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.

  • 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 5800X/Gigabyte B550m DS3H/32GB RAM@3600MHz/Radeon HD7770 OC/Asus Xonar SE/108TB HDD+512GB Samsung 980 Pro+2TB Crucial SSD/28" Samsung 4k
    TerraMaster F4-421 mit 28TB
    XBox Classic/360S/Series X/PS3 Super Slim 500GB/PS4 Pro (XBL-ID: jacdelad, PSN: jacdelad84)
    OnePlus 6 8GB/256GB
    jacdelad.bplaced.net

  • Diesen Zeitverlust hast du aber auch, wenn du den Code in einer extra Schleife
    abarbeitest, bzw. in dieser eine Proc aufrufst. Wie extrem das nun in der
    Move-Funktion aussieht, weiß ich leider nicht. Wir arbeiten ja hier mit XProfan
    und nicht mit dem darunter liegenden Delphi-Code.

  • Das kannst Du ja ungefähr abschätzen. Was Du als Callback haben willst, hast Du ja schon geschrieben. Nun also nur mit einer realen Liste

    Code
    WhileLoop GetCount(Liste) -1
      MeineFunktion
    EndWhile

    Dann siehst Du ja schon, wie lange das dauert.



    Gruß Volkmar

  • 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 !!!!!!