Model / View "Lazy population" eines TreeViews (Konzept)

Alles rund um die Programmierung mit Qt
Antworten
CBM
Beiträge: 38
Registriert: 6. Mai 2009 19:09

Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von CBM »

Hallo,

obwohl ich schon mehrere Tage mit Model/View rumspiele, stellt sich mir eine grundlegende Frage, wie man vom allgemeinen Ansatz folgendes Problem angehen sollte:

Ausgangslage
In einer SQL-Datenbank liegen ca. 30000 Datensätze. Jeder Datensatz ist später eine Zeile ein einem TreeView. Die Datensätze sind unsortiert aber es besteht zwischen diesen eine Hierarchie, die später auch im TreeView berücksichtigt werden soll. Diese Hierachie ist dadurch erkennbar, dass bei jedem Datensatz angegeben ist, wer sein Parent ist.

Gemachte Erfahrungen
Alle meine bislang gemachten Ansätze laden auf einmal alle 30000 Zeilen, was jedoch beim Aufbau der Tree-Hierarchie einfach zu lange dauert (ca. 2 min.). Da erscheint ein stückchenweiser Aufbau des TreeViews doch sinnvoller.

Konzeptionelle Überlegungen
Jeder Datensatz (=jede Zeile später im TreeView) wird einem Item entsprechend. Also werde ich hierfür QAbstractItemModel ableiten. Die Items werden jedoch erst dann erzeugt, wenn diese angezeigt werden sollen. Das wäre ja zunächst nur mal die erste Ebene. Erste Ebene = alle Parent-Items, die direkt am RootItem hängen; Aber halt. Ich muss doch bereits jetzt bei diesen Parent-Items anzeigen, ob man diese aufklappen kann. Also dann werde ich auch jetzt schon die zweite Ebene laden (=die Child's der ersten Parents). Klappt man nun ein Item der ersten Ebene auf, bekommt man die bereits geladenen Daten angezeigt und lädt dann zugleich von diesem Item die dritte Ebene. Das Spiel ging dann immer so weiter. Soviel zu meiner Theorie. Meine Frage: Total falscher Ansatz? Geht's eleganter? Wie machen es die Profis (zu denen ich definitiv nicht gehöre)?

Hier, dass Ganze nochmals grafisch dargestellt:
Bild
https://picasaweb.google.com/lh/photo/d ... directlink

(Achja... die Docu habe ich natürlich schon gewälzt. In der wird auch angegeben, dass fetchmore() / canfetchmore() / lazy population die Lösung ist ... wie diese aber selbst aus konzeptioneller Sicht am besten aussieht ... nun, dafür dieser Thread :D
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von upsala »

Verschiedene Ansätze:

1. Nur die Primär-Schlüsel aus der Datenbank laden den Tree damit aufbauen und bei Bedarf dann den Rest der Datenzeilen (aber die Datenzeilen auch Blockweise sonst wirds wieder langsam)

2. Oder eben canFetchMore() / fetchMore(): Bei canFetchMore() immer true zurückliefern und bei fetchMore() die Daten aus der Datenbank in interne Puffer laden. Außerdem bei fetchMore() ein Flag setzen, damit man bei canFetchMore() überprüfen kann, ob die Daten noch nachgeladen werden müssen und ab diesem Moment kann man bei canFetchMore() false zurückliefern.
CBM
Beiträge: 38
Registriert: 6. Mai 2009 19:09

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von CBM »

okay, dann werde ich zunächst mal den Ansatz so wie eingangs beschrieben verfolgen und den zweiten von upsala angedeuten Weg mit Fetchmore() angehen.
Also mein ersten Schritte:

(1) Lade aus der Datenbank nur die Parent-Items (=1. Ebene);
(2) Iteriere durch die einzelnen Parent Items und suche zu jedem Parent-Item in der Datenbank mögliche Childs;
(3) Ergänze die Childs zu den Parents im Model;

Wenn das geht, dürfte als nächstes wohl anstehen
(4) Prüfe, ob ein Item welches Childs hat, expanded wurde. Vielleicht über Events oder Signals? Mal schauen.
(5) Klappe eine weitere Ebene des Astes auf und lade die bereits darunter liegende Ebene aus der Datenbank nach, um zu wissen und anzuzeigen, ob man weiter aufklappen kann.

Ich denke die erste Programmierhürde dürfte (2)-Schritt sein: das Durchiterieren durch alle Items der ersten Ebene (wird wohl die Arbeit fürs WE :cry: ).
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von upsala »

canFetchMore / fetchMore wird im übrigen schon für die erste Ebene aufgerufen.

Hattest du zuvor hier nicht noch einen anderen Text stehen? Dort hattest du auf das Simple-Tree-Example verwiesen gehabt, dies ist sehr gut geeignet um darauf aufzubauen. Damit kannst du dir auch mal die Reihenfolge der canFetchMore / fetchMore-Aufrufe ansehen.
CBM
Beiträge: 38
Registriert: 6. Mai 2009 19:09

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von CBM »

Ja richtig, ich hatte hier noch eine weitere Frage stehen ... habe diese dann aber wieder gelöscht, da ich dachte "ich sollte mehr selbst erarbeiten, anstatt gleich im Forum um Hilfe zu schreien."

Ich habe jetzt mal mit dem Simple Tree Model aus der Doku (http://doc.qt.nokia.com/4.7/itemviews-s ... model.html) rumgespielt. Diese habe ich dann auch um canFetchMore (und fetchMore) erweitert. Zunächst nur als Dummy-Funktionen, die lediglich ein "qDebug() << "blabla" enthalten. Dabei fällt auf, dass canFetchMore() beim aufklappen eines Items jedesmal genau 3x aufgerufen wird. Ich weiß zwar jetzt noch nicht wie wichtig dies für mein reales Projekt sein wird, würde aber trotzdem gerne verstehen warum genau 3x.

Jedenfalls denke ich sieht das allgemeine Konzept jetzt so aus:
In der Funktion canFetchMore() werden alle sichtbaren Items überprüft, ob diese Parent-Items sind. Zum Prüfen, ob ein Item überhaupt bereits sichtbar ist, sollte die Funktion QTreeView::isExpanded dienlich sein. Somit wird mir canFetchMore() eine QListe nur derer Items liefern, die überhaupt als nächtes aufgeklappt werden können. Diese QListe übergebe ich dann gleich an FetchMore(), wo die Datenbankabfrage durchgeführt wird und die neuen Child-Items erzeugt werden. Somit bevorratet das Model immer nur exakt eine weitere Stufe und zwar auch nur von den bereits angezeigten Parent-Items. Da canFetchMore() sicherlich nach jedem Expand neu aufgerufen wird, bleibt das Ganze auch stets aktuell.

Nachtrag: .... und das ist doch eigentlich auch so, wie es upsala bereits oben beschrieben hat (nur Kürzer). Sorry, habe mal wieder eine gaaannnnnzzzz lange Leitung:
upsala hat geschrieben:2. Oder eben canFetchMore() / fetchMore(): Bei canFetchMore() immer true zurückliefern und bei fetchMore() die Daten aus der Datenbank in interne Puffer laden. Außerdem bei fetchMore() ein Flag setzen, damit man bei canFetchMore() überprüfen kann, ob die Daten noch nachgeladen werden müssen und ab diesem Moment kann man bei canFetchMore() false zurückliefern.
Zuletzt geändert von CBM am 27. August 2011 11:19, insgesamt 2-mal geändert.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von upsala »

Da man das Flag für canFetchMore() zwischenpuffern sollte/kann dürfte dies kein Problem sein.

Laut Qt-Sourcen interessieren sich expand u. horizontal/vertical-Slider für canFetchMore(), deswegen die häufigen Aufrufe.
CBM
Beiträge: 38
Registriert: 6. Mai 2009 19:09

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von CBM »

Kurze Zwischenfrage, deren Antwort auch zukünftig hilfreich sein könnte:
upsala hat geschrieben: Laut Qt-Sourcen interessieren sich expand u. horizontal/vertical-Slider für canFetchMore(), deswegen die häufigen Aufrufe.
wie findet man sowas schnell raus? Hast du die ganzen Qt-Sourcecodes nach canFetchMore() durchsucht???
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Re: Model / View "Lazy population" eines TreeViews (Konzept)

Beitrag von upsala »

Sicher, dafür wurde grep doch entworfen, oder?
Antworten