![]() |
ListView: Wie erkennt man, dass Elemente fertig eingetragen?
Hallo!
Wir haben folgendes Problem: Wir tragen in die ListView Ergebnisse aus einem Ethernet Scan ein. Wissen daher nicht wirklich, wann die Antworten kommen. Haben daher das ganze mit einem Timer gelöst, der die folgende Aktion nach 500 ms nach dem letzten Eintrag ausführen soll (Timestamp bei Schreibebeginn und timesince). Wenn die Einträge in der Liste drinnen sind und nach 500 ms nichts neues mehr kommt (also der Timer nicht mehr auslöst), dann wollen wir die Spalten (Columns) auf die optimale Breite setzen (sprich den Text in den jeweiligen Columns hinsichtlich ihrer Länge analysieren und daraus die rrichtige Spaötembreite ermitteln.). Das funktioniert, detto, dass wir Spalten ohne Einträge auf 0 setzen (also ausblenden). Nun haben wir aber das Problem, dass wir einen Indexüberlauf bekommen. Beim Debugen sehen wir, dass die zu behandelnde Spalte einen Index um 1 größer hat, als gerade verfügbar ist. Insgesamt haben wir 15 Spalten, die erste ist die Caption und dann (über die Subitems) von 0 bis 14. Nun kanns mir aber passieren, dass ich bei Subitem(12) eine Exception wegen Indexüberlauf bekomme. Soll heißen, dass wir davon überzeugt sind, dass das Schreiben scheinbar doch noch nicht fertig war. Daran knüpft nun meine Frage an: Gibt es in Delphi eine Möglichkeit festzustellen, ob noch auf eine ListView geschrieben wird respektive ob das Schreiben schon fertig ist (sowas wie ein Event "Drawfinished" - in die ListView schreiben ist ja eigentlich auch nichts anderes als ein Draw Event (wird einem erst beim Umfärben einzelner Einträge bewußt). Ich muss also scheinbar erst schauen, ob auch wirklich fertig eingetragen wurde. Denn sonst ändert sich der Index während der Bearbeitung und Delphi meckert daw an. Ich suche also ein Event oder eine Funktion, an Hand der ich erkenne, dass die ListView fertig geschrieben ist und ich mit meinem Sizer drüber kann, ohne einen Indexüberlauf auf Grund noch fehlender Spalten zu riskieren. Wenn jemand von Euch hierzu hilfreiche Tipps hätte, wäre mir sehr geholfen. Danke schon im Voraus! Lg, Stephan. |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
Hi Stephan!
Zitat:
Ich glaube, das ein Rechenfehler eurerseits Schuld ist. Zitat:
Vielleicht ist es aber auch ein Schreibfehler im Post. :) |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
ups ja stimmt, das mit 0-14 war ein typo. die indizes sind korrekt. allerdings dürfte der draw event noch nicht fertig sein.
wie kann ich feststellen, dass das passiert ist und ich nicht auf eine "unfertige" listview zugreife. das dürfte bei uns nämlich der fall sein, denn bei listview.columns.count wissen wir ja, wieviel spalten wir haben. und wenn ich auf das subitem[i-1] zugreife, dann passt das ja so. nur dürften einige der subitems durch den drawevent noch nicht fertig sein. denn wie gesagt: ich will die spalten sizen (optimale grösse bzw. zuschieben auf 0 wenn leer). und das darf ich klarerweise erst dann, bis sich die listview nicht ändert, weil sich sonst die indizes ändern und ich eine indexüberschreitung bekomme (passiert jedesmal beim subitem). da der index aber vom column.count abhängt (mit -1 klarerweise) sollte der index auch passen. also muss ich den drawevent abwarten. wie stelle ich das aber fest. signalisiert mir delphi das irgendwie? wenn ich z.b. einen timeout seit dem letzten elementeintrag von 750 ms mache, dann gehts, nur ist der erste listeneintrag grauslich, weil es eine dreiviertel sekunde dauert, bis das sizen anfängt. lg, stephan. |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
hallo, macht ihr das threaded? dann wäre die verwendung von critical sections empfehlenswert.
|
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
das ist es ja, wir haben um den listaufbau (nennen wir display) die critical section gelegt. darin bleiben wir aber hängen (deadlock) wenn es beim resizen kracht.
oder meinst du das sizen in eine eigene critical section? |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
Hallo, ihr habt diesen Ablauf:
- multithreaded einfügen - sobald das einfügen beendet ist, resizen right? wenn ihr eine codestelle habt, an der ihr definitiv sagen könnt, das einfügen ist abgeschlossen, dann legt eine Criticalsection an, die am anfang des einfügens angefordert und am ende releast wird. Ein Thread wartet dann nur auf diese CriticalSection (indem er sie anfordert). Sobald er sie bekommt sendet er eine Windows-Message an den Hauptthread, indem als Reaktion auf diese Message das Sizing vorgenommen wird. Kleine Zwischenfrage: Benutzt ihr bereits BeginUpdate und EndUpdate für die Listview/die subitems? wenn ihr keine solche codestelle habt, dann braucht ihr eine generelle "listview-access" critical section. Immer, wenn irgendjemand (sprich, irgendein thread) an die listview ranwill, muss er die critical section betreten. damit kann es eigentlich niemals zu zugriffsfehlern kommen. Wenn ihr vor Beginn des Scans abschätzen könnt, wie viele Antworten ihr bekommt (bei entsprechender designmöglichkeit auch fehlschläge mit einberechenn und rückmelden!), kannst du da ja noch eine hürde einbauen, die erst nach entsprechender anzahl eingegangener ergebnisse (oder einem master timeout) mit dem sizing anfängt. BTW: Zitat:
|
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
hm und wie mach ich das dann sinnvoll, wenn die einträge zu unterschiedlichen zeiten daherkommen, also je nachdem wann die antwort über tcp retour kommt?
wenn ich einen zeitraum habe, in der ich alle antworten aufsammle, sollte das kein problem sein. aber wenn z.b. eine antwort 5 sec nach der vorherigen kommt, dann nutzt mir das begin und endupdate auch nur bedingt etwas, ganz abgesehen davon dass wirs auch drinnen haben. das sonderbare dabei (unserem problem) ist aber, dass der crash immer bei unterschiedlichen indexwerten passiert, also mal gleich beim ersten element, mal beim letzten, mal gleich beim ersten subitem, mal beim 10. und dann auch wieder mal garnicht. schaut daher stark nach "netten" racingconditions aus. deshalb war auch meine überlegung, dass das sizen erst dann beginnen darf, wenn die listview sich nicht mehr ändert, also alle einträge drinnen sind und das draw event fertig ist. dann kann mit dem index nichts mehr passieren. aber scheinbar wird unser sizer schon aktiv, bevor der draw event fertig ist. stellt sich also (wie schon zu beginn) die frage: wie kann ich feststellen, dass die element fertig eingetragen sind und der draw event abgeschlossen ist und ich keine indexverletzung mehr riskiere. critical section und begin sowie endupdat haben dabei leider auch nur "bedingt" geholfen. |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
Guten Morgen Stephan,
ich bin sicher, dass die geschilderten Probleme durch einen Implementierungsfehler in "deinem" Programm entstehen. Eine racing condition mit dem internen Zeichenvorgang kann eigentlich nicht vorliegen. Du solltest es mit einer Detailanalyse versuchen. Trenne das Multithreading vom Listview-Handling und untersuche die Problemfelder getrennt voneinander. Die ListView exportiert die Ereignisse OnDeletion() und OnInsert(), die dir die Möglichkeit zu Berechnungen geben. Ein wiederholtes Resizing der Spalten halte ich aber für sehr unangenehm. Üblich ist eine statische Dimensionierung oder - bei häufigen Änderungen am Inhalt - ein Resizing durch den Benutzer über die vorgesehenen Shortcuts (CTRL +). Grüße vom marabu |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
was ich bis jetzt noch vergessen habe ist, dass wir im resizer auch einen "canvas invalid handle" bekommen.
wenn ich das resizen nach jedem einzelnen eintrag aufrufe (also n mal bei n einträgen - was allerdings sehr rechenaufwändig und nicht schön ist) dann funktioniert es problemlos. hab das jetzt mit 750 ms timeout seit dem letzten ankommenden element gelöst und das funktioniert stabil. würde mich aber trotzdem interessieren, ob es einen event gibt, der seitens delphi signalisiert, dass das zeichnen (draw event) fertig ist. |
Re: ListView: Wie erkennt man, dass Elemente fertig eingetra
greifst du vom Thread aus auf die Listview eventuell ohne Syncronize zu? anders kann ich mir "canvas invalid handle" nicht erklären.
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:49 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz