Referenz zwischen Tree-Items und Objekten

Alles rund um die Programmierung mit Qt
Antworten
Toru
Beiträge: 10
Registriert: 27. April 2008 18:56

Referenz zwischen Tree-Items und Objekten

Beitrag von Toru »

Hi,

also ich hatte mich in meinem ersten Posting wohl ein wenig missverständlich ausgedrückt - deshalb noch einmal.

In meinem Modell habe ich eine verlinkte Liste, die mir die Daten für meine TreeView liefert (siehe Simple Tree Model Example [hier im Speziellen treeitem.h]).

Nun habe ich aber auch noch eine Liste von Objekten (Beispiel):

Code: Alles auswählen

class Foobar
{
protected:
        int foo;
public:
        void setFoo(int);
        int foo(void) const;
};
Wenn ich in meine verlinkte Liste "hineinschaue", finde ich also irgendwo den Wert für foo, d.h. die Attribute und ihre Wert meiner Objekte liegen in der verlinkten Liste. Wenn sich nun in meiner verlinkten Liste ein Attribut ändert (zum Beispiel, weil der Benutzer in der View einen Wert geändert hat), will ich natürlich auch das Attribut in meinem entsprechenden Objekt ändern, d.h. ich brauche irgendwie eine Referenz von Eintrag in verlinkter Liste zu Objekt. Wir würdet ihr das machen?

Toru
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

Deine Beschreibung ist etwas schwer zu verstehen finde ich.

Ein View hat zu keinem Zeitpunkt mehr Daten als das Model.
Es ist möglich dem Benutzer durch den Controller Daten des Models verändern zu lassen. Hast du Daten des Models geändert, kannst du im Model mit QAbstractItemModel::dataChanged() bzw. QAbstractItemModel::layoutChanged() die Views über Änderungen informieren. Die Vews rufen dann über die Model-Schnittstellen (data(), flags() usw.) die neuen Informationen ab.

Wenn du mit den Daten des Views arbeitest, hast du üblicherweise einen QModelIndex zur Verfügung. Über den ModelIndex kannst du auf Dein Objekt schließen:

Code: Alles auswählen

static_cast<FooBar*>(index.internalPointer())
In der Praxis hat es sich für mich als Sinnvoll erwiesen jedem Objekt zusätzlich eine ID zu geben, z.B. "FooBar_0001" (diese IDs ergeben sich z.B. beim Einlesen der Daten aus INI-Files oder der Datenbank. Ich habe meine Models dann einfach noch um eine Komfortfunktion erweitert die in etwa so aussieht:

Code: Alles auswählen

FooBar* getFooBar(QString fooBarID);
Das Mapping zwischen ID und FooBar* mache ich anhand eines QHash<QString, FooBar*> in meinem Model. Die Zuordnung wird erzeugt während ich die Daten meines Models einlese.


Ich hoffe das bringt Dich etwas weiter.

Ciao,
Sephral
Toru
Beiträge: 10
Registriert: 27. April 2008 18:56

Beitrag von Toru »

In welcher Form hältst du deine Daten im Modell? Als Baum resp. verlinkte Liste?
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Toru hat geschrieben:In welcher Form hältst du deine Daten im Modell? Als Baum resp. verlinkte Liste?
Primär ist alles in Baumstrukturen organisiert (Parents & Children, wie im Qt-Beispiel). Die Visualisierung findet bei mir auch mit QTreeViews statt.

Intern verwende ich zusätzlich einen QHash mit Pointern auf meine TreeItems um Datenobjekte schnell zu finden, falls ich etwas ändern möchte. Diesen schnellen "Rückweg" benötige ich, da ich Änderungen an den Daten über Mengenoperatoren realisiert habe (z.B. "Ändere bei allen TreeItems, deren ID auf QRegExp(...) passt und die vom Typ XYZ sind, den Parameter "alertState" auf "true").

Ciao,
Sephral
Toru
Beiträge: 10
Registriert: 27. April 2008 18:56

Beitrag von Toru »

Sephral hat geschrieben:
Toru hat geschrieben:In welcher Form hältst du deine Daten im Modell? Als Baum resp. verlinkte Liste?
Primär ist alles in Baumstrukturen organisiert (Parents & Children, wie im Qt-Beispiel). Die Visualisierung findet bei mir auch mit QTreeViews statt.

Intern verwende ich zusätzlich einen QHash mit Pointern auf meine TreeItems um Datenobjekte schnell zu finden, falls ich etwas ändern möchte. Diesen schnellen "Rückweg" benötige ich, da ich Änderungen an den Daten über Mengenoperatoren realisiert habe (z.B. "Ändere bei allen TreeItems, deren ID auf QRegExp(...) passt und die vom Typ XYZ sind, den Parameter "alertState" auf "true").

Ciao,
Sephral
Wenn ich das richtig verstanden habe, arbeitest du also lediglich mit dem Baum. Soweit gibt es natürlich auch kein Problem. Das hat allerdings nur wenig mit Objektorientierung zu tun (muss es ja auch nicht unbedingt). Was aber nun, wenn Objektorientierung ins Spiel kommt und du die Attribute deiner Objekte mit den Werten aus deinem Baum belegen möchtest? Genau das ist mein Problem! Wie schaffe ich die Synchronisation zwischen Wert im Baum und Wert des Attributes im Objekt?
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

du hast das falsch verstanden :-)

Die synchronisation zwischen View und Model geschieht über das Interface von QAbstractItemModel.

Schau Dir doch noch mal in Ruhe Doku zum MVC-Pattern an und dann wie es in Qt realisiert wurde. Das hat ne ganze Menge mit Objektorientierung zu tun :-)


Ansonsten zeig und doch einfach mal ein wenig Quellcode...


Ciao,
Sephral
Toru
Beiträge: 10
Registriert: 27. April 2008 18:56

Beitrag von Toru »

Sephral hat geschrieben:Hallo,

du hast das falsch verstanden :-)

Die synchronisation zwischen View und Model geschieht über das Interface von QAbstractItemModel.

Schau Dir doch noch mal in Ruhe Doku zum MVC-Pattern an und dann wie es in Qt realisiert wurde. Das hat ne ganze Menge mit Objektorientierung zu tun :-)


Ansonsten zeig und doch einfach mal ein wenig Quellcode...


Ciao,
Sephral
Ich habe die Beziehung Model <-> View durchaus verstanden - darum geht es nicht! Es geht darum, dass du in deinem Model als Datenstruktur lediglich einen Baum hältst. Wo liegen deine _benutzerdefinierten_ Objekte, die aus dem Baum ihre Attribute "füttern"? Wenn du keine hast, dann gibt es natürlich auch kein Problem.
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Hallo,

ich habe in jedes TreeItem noch ein Datenobjekt eingehängt (TreeItemData).
TreeItemData ist die Basisklasse für mehrere abgeleitete Klassen die mittels einer Factory erzeugt werden. Je nach Typ des TreeItems (hat natürlich ein type-property) kann ich dann das TreeItemData passend casten oder allgemeine Informationen über das Interface der Basisklasse abfragen.

Wenn die Views über das Model-Interface (data(), flags() usw) Inforrmationen haben wollen, dann werte ich das Data-Objekt des TreeItems aus und setze abhängig davon dann Icons, Tooltips usw.

Bei einfachen Datenmodellen kann man auch die Daten z.B. direkt in das TreeItem packen.

Der Ansatz über das TreeItemData musste bei mir sein, da ich in einem Baum viele verschiedene Typen von Items visualisiere und ich zu jedem Typ ne ganze Menge Daten bereit halten muss. Jeder Typ hat spezielle Auswirkungen in der GUI was z.B. Kontextmenüs angeht bzw die mit diesem Typ möglichen Aktionen.

Ich habe dann noch abgeleitete QTreeViews, die quasi den Controller implementieren und abhängig vom Typ des aktuell ausgewählten TreeItems noch einige Spezialitäten regeln.


Ciao,
Sephral
Toru
Beiträge: 10
Registriert: 27. April 2008 18:56

Beitrag von Toru »

Das mit dem TreeItemData-Objekt klingt einleuchtend. Klar könnte man bei einfachen Modellen die Daten direkt in die TreeItems stecken, was ich aber persönlich nicht so gut finde, weil das wenig mit Objektorientierung zu tun hat.

Danke für deine Idee. Mich würde allerdings interessieren, ob es da nicht einen allgemeingültigen Ansatz zur Synchronisation zwischen TreeItems und benutzerdefinierten Objekten gibt.
Toru
Beiträge: 10
Registriert: 27. April 2008 18:56

Beitrag von Toru »

Sephral hat geschrieben:Hallo,

ich habe in jedes TreeItem noch ein Datenobjekt eingehängt (TreeItemData).
TreeItemData ist die Basisklasse für mehrere abgeleitete Klassen die mittels einer Factory erzeugt werden. Je nach Typ des TreeItems (hat natürlich ein type-property) kann ich dann das TreeItemData passend casten oder allgemeine Informationen über das Interface der Basisklasse abfragen.
Darf ich fragen, wie du die type-property implementiert hast?
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Toru hat geschrieben: Darf ich fragen, wie du die type-property implementiert hast?
Klar darfst du, es handelt sich einfach um enums.

Das TreeItem verfügt über einen Pointer auf das Data-Objekt und das Data-Objekt verfügt wiederum über einen schöden enum der den Typ definiert.

Code: Alles auswählen

protected:
TreeItemData*              m_pTreeItemData;

Code: Alles auswählen

protected:
eTreeItemDataType	m_eDataType;
Über eine get-Methode kann ich vor dem Zugriff auf das Data-Objekt den Typ abfragen und, falls notwendig, entsprechend casten.

TreeItemData ist wie gesagt die Basisklasse für mehrere Ableitungen. Die wichtigsten Parameter kann ich direkt von der Basisklasse abfragen und kann mir somit das casten auf den eigentlichen Typ in vielen Fällen sparen. Das Erzeugen der TreeItemData-Objekte geschieht über ein Factory-Pattern direkt beim Einlesen meiner Konfigurationsdateien (bzw Datenbanken).


Ciao,
Sephral
Antworten