Hilfe beim Auslesen einer externen Listbox

  • VB.NET
  • .NET 4.5

Es gibt 26 Antworten in diesem Thema. Der letzte Beitrag () ist von Regular_vb_user.

    Regular_vb_user schrieb:

    Stimmt das so ?
    Tut mir leid, das kann ich so nicht sagen.
    Ich müsste höchstens selbst mal probieren, das Ding auszulesen, aber das geht momentan nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Da ich auch mal mit Fremdprogrammmanipulation rumhantiert habe, war ich bis jetzt interessierter Mitleser. Der Knackpunkt beim letzten Problem hingegen dürfte aber eher folgendes eigenes Codeproblem sein:

    VB.NET-Quellcode

    1. For lIndex = 0 To lCount - 1
    2. lLen = SendMessage(ChildHandle, LB_GETTEXTLEN, lIndex, 0&)
    3. sItem = Space(lLen)
    4. Call SendMessage(ChildHandle, LB_GETTEXT, lIndex, sItem)
    5. ListBox1.Items.Add(sItem.ToString)
    6. Next

    Anstatt zu versuchen, immer alle Zeilen einzulesen, habe ich einen Kurzzeittimer eingebaut, der nur die Zeile X einliest, beginnend bei 0. Wenn die per lCount = SendMessage(ChildHandle, LB_GETCOUNT, 0&, 0&) zurückgegebene Zahl der ListBox-Zeilen <= X ist, wird nix gemacht, ansonsten wird die Zeile X mit aus der ListBox ausgelesen und X um 1 erhöht. Dadurch wird gewährleistet, dass man am Ende sehr schnell immer nur die unterste Zeile einliest und nicht immer den ganzen ListBox-Inhalt (was bei vielen Zeilen recht inperformant wäre). Es kommt natürlich auf das ListBox-Verhalten an.
    1. Wenn sich alle 3 Sekunden der komplette 50-Zeilen-Inhalt (keine Ahnung, wieviele es wirklich sind) ändern würde, käme nur die For-Loop-Variante von @Regular_vb_user infrage.
    2. Wird immer was an die Zeilen als neue Zeile drangehangen, dann wie beschrieben.
    3. Wird irgendwann, wenn die Box voll ist, die 1. Zeile gelöscht und die neueste Zeile angehangen, muss X irgendwann konstant bleiben.

    btw: Option Strict On verwenden
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    @VaporiZed
    Vielen Dank für die Rückmeldung und deine Lösungsansätze.
    Ich muss dazu sagen, dass ich den geposteten Code erst aus Testgründen verwendet hatte.
    Um überhaupt mal eine komplette Listbox auslesen zu können.
    Allerdings habe ich dort bereits schnell gemerkt das die Abfrage sehr lange dauert.
    Bereits bei einer For Limitierung auf die ersten 10 Listboxeinträge dauert das einen Moment.

    Zum Verhalten der auszulesenden Mistbox/Listbox :) kann ich nur sagen, dass diese super speziell ist.
    Es können innerhalb eines Bruchteils einer Sekunde schnell mal bis zu 60+ Einträge dazu kommen.
    Außerdem leert sich die Listbox nicht und es waren schnell mal 4000+ Einträge bei kurzzeitigen Tests.
    Ich möchte mit diesem ganzen Thema die Informationen filtern und dies möglichst in Echtzeit.
    Die von dir erwähnte Methode über einen Kurzzeittimer habe ich in ähnlicher Form bereits getestet, was auch in erster Line super läuft ^^.
    Allerdings denke ich das ich, auch wenn ich nicht gerade ein Fan von bin, nicht auf eine For - Schleife verzichten kann.
    Hier mal meine aktuelle Methode:

    VB.NET-Quellcode

    1. lCount = SendMessage(ChildHandle, LB_GETCOUNT, 0&, 0&)
    2. If lCount = mycounter Then
    3. 'Unverändert
    4. Else
    5. 'Neuer Eintrag
    6. lLen = SendMessage(ChildHandle, LB_GETTEXTLEN, lIndex, 0&)
    7. sItem = Space(lLen)
    8. Call SendMessage(ChildHandle, LB_GETTEXT, lIndex, sItem)
    9. ListBox1.Items.Add(sItem.ToString)
    10. mycounter = lCount
    11. End If

    Dabei ist es allerdings so, dass mehrere Listbox Einträge übersprungen/ignoriert werden.
    Ich denke das ich deswegen einen langsameren Timer machen muss der immer die neuen Einträge liest.

    In etwa so:

    VB.NET-Quellcode

    1. newCount = lCount - mycounter
    2. For lIndex = 0 To newCount
    3. '...
    4. Next

    An Option Strict On hatte ich nicht gedacht, danke für die Info. :)
    Du liest die Nachricht mit dem Index lIndex ein. Ich jedoch mit mycounter. Ggf. kommt bei Dir dadurch das überspringen. Der Timer kann ja auch auf 1 ms gestutzt werden. Oder gar kein Timer, sondern in einem Extra-Thread. Ich hab mir mal was gebastelt, was ich heute abend nochmal austesten werde. Aber beim besten Willen: Für wen sind denn in kurzer Zeit > 60 Einträge pro Sekunde gedacht?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Naja wie gesagt, die Listbox stammt von einem Spiel^^
    Es werden dort Spieler, NPC, Flags angezeigt. Und zwar von jedem einzelnen Objekt. Also 30 Einträge sind da schnell erreicht und das nur bei kleinen Gebieten. :/

    Hier mal ein kleines Beispiel..

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Regular_vb_user“ () aus folgendem Grund: Bild geändert

    Jupp. Hab's mal mit > 60 Einträgen pro Sekunde probiert und alle erfasst:

    VB.NET-Quellcode

    1. Dim stopp As Boolean = False
    2. '...
    3. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Await Task.Run(Sub()
    5. Do
    6. If stopp Then Exit Do
    7. lCount = SendMessage(ChildHandle, 395, IntPtr.Zero, Nothing)
    8. If lCount <= alreadyGot Then Continue Do
    9. lLen = SendMessage(ChildHandle, 394, alreadyGot, Nothing)
    10. sItem = Space(lLen)
    11. SendMessage(ChildHandle, 393, alreadyGot, sItem)
    12. Me.Invoke(Sub() ListBox1.Items.Add(sItem.ToString))
    13. alreadyGot += 1
    14. Loop
    15. End Sub)
    16. End Sub

    Hab die Konstanten durch ihre Werte ersetzt und Space ist ja VB-NameSpace, also ggf. ersetzen, aber läuft wie gewünscht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Funktioniert wirklich gut. :)
    Allerdings geht es bei mir auch nur auf einer Test Listbox Anwendung unter 1 Sekunde.
    Ich glaube mittlerweile das die ListBox die ich auslesen möchte, durch die schnelle Aktualisierung den Prozess verzögert.
    Habe es mal mit deaktivieren und aktivieren der Listbox beim auslesen versucht.

    Vor der Schleife:

    VB.NET-Quellcode

    1. EnableWindow(Hwnd, False)

    Und danach:

    VB.NET-Quellcode

    1. EnableWindow(Hwnd, True)

    Kommt mir damit schneller vor.

    Habe es mal mit Stopwatch gemessen.
    Für genau 50 Listboxeinträge braucht es ganze 13 Sekunden !!
    Keine Ahnung wieso die externe Listbox so träge ist :(

    #Edit 7.10.17 :
    Ich hab mal nochmal bisschen rumgespielt und festgestellt das dein Code wirklich hervorragend funktioniert.
    Es werden zwar nicht direkt innerhalb einer Sekunde 60 Einträge hinzugefügt (liegt nicht am Code), allerdings sehe ich es in Echtzeit sobald was neues erscheint.
    Zusammen mit einem kleinen Filtersystem was ich mir erstellt habe, läuft es wirklich sehr gut :)
    Danke

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Regular_vb_user“ () aus folgendem Grund: Neue Erkenntniss :)