Seite 1 von 1

Heterogene Datensammlung als QAbstractItemModel

Verfasst: 25. Januar 2006 10:24
von Kris
Hallo zusammen,

ich suche eine Lösung für folgendes Problem :
Ich will ein Model für eine Sammlung heterogener, hierarchischer Daten
erstellen, die dann an ein QTreeView, QTableView o.ä. angebunden werden sollen.
Die Klassen der Daten sehen ungefähr wie folgt aus :

Code: Alles auswählen

class Org : public QObject {
...
private:
QString orgid;
QList<Org *> suborgs;
QList<Material *> matliste;
QList<Personal *> orgpersliste;
};

class Material : public QObject {
...
private:
QString matid;
...
};

class Personal : public QObject {
...
private:
QString persid;
...
};
Es soll nun ein Baum (zur Navigation) aufgespannt werden,
der etwa wie folgt aussieht :

Code: Alles auswählen

/
|
|-Org1
|    |- OrgBeschreibung
|    |- Personal
|    |       |- Kris
|    |       |- Foo
|    |       |- Bar
|    |- Material
|    |       |- Säge
|    |       |- Hammer
|    |       |- Dosenöffner
|    |
|    |- Org 1.1
|            |- OrgBeschreibung
|            |- Personal
|            |- Material
|- Org 2
Ich komme allerdings zur Zeit nicht so gut mit der
Implementierung des Models klar, da alles was ich an
Beispielen gesehen habe (Simple Tree Model,
Simple DOM Model), darauf basiert, dass im Baum
nur gleichartige Daten(TreeItems oder DomItems)
eingehängt werden. Gibt es eine Möglichkeit, das QAbstractItemModel so abzuleiten, dass es auch mit verschiedenen Klassen
klar kommt ?
Die Möglichkeit, über einen Member der Klasse Org einen Baum,
der ausschließlich TreeItems enthält, zu generieren und an ein
TreeModel zu übergeben, besteht natürlich, baut aber eine
Parallelstruktur zum eigentlichen Datenbestand auf, die ich gerne vermeiden möchte.

Für Tipps und Hinweise immer dankbar,


Kris

Verfasst: 26. Januar 2006 02:04
von Esleborn
ja da gibt es eine Möglichkeit! Hab selbst grad erst eine Implementiert...

Ich hab das wie folgt gemacht:
Alle Daten-Klassen leiten sich von einer einzigen Klasse ab (C_DataItem), welche die unten stehende Funktionalität hat.

Code: Alles auswählen

class C_DataItem
{
public:
  C_DataItem ( );
  virtual ~C_DataItem ( );

  virtual bool AppendChild ( C_DataItem *fp_child, bool f_copy = false );   // --> Hängt ein Child an, falls unmöglich gibt es false zurück; f_copy ist true, wenn das C_DataItem kopiert werden soll, ist false, wenn es verschoben werden soll...

  virtual C_DataItem * Child ( int f_row );   // --> Gibt das Child an der übergeben Stelle zurück, falls nicht vorhanden NULL
  virtual int Childs ( ) const;   // --> Anzahl der "Childs"
  virtual int Columns ( ) const;   // --> Anzahl der Spalten (unterschiedliche Daten, zB bei einer Tabelle)
  virtual QVariant Data ( int f_column ) const;   // --> Gibt die Daten zurück, siehe unten
  virtual bool Data ( int f_column, QVariant f_data );   // --> Setzt Daten, siehe unten
  virtual int Row ( ) const;   // --> Gibt die eigene Nummer im Parent zurück, falls kein Parent, dann 0
  virtual C_DataItem * Parent ( );   // --> Gibt den Parent zurück, wenn's keinen gibt: NULL
};
Bei der implementierung muss Append Child ein SubItem "in" das Item einfügen, ist dies unöglich gibt es false zurück. Ein Kopieren ist zum Beispiel normallerweise der Fall wenn mit gedrücktem SHIFT etwas gedroppt wurde.
Data gibt/setzt Daten der entsprechenden Spalte...


Jetzt musst du noch das QAbstractItemModel erstellen...:

Code: Alles auswählen

class C_HierachyModel : public QAbstractItemModel
{
 Q_OBJECT
public:
  C_HierachyModel ( C_DataItem *fp_rootItem = NULL, QObject *fp_parent = NULL );  // <-- fp_rootItem ist jetzt der Root
  ~C_HierachyModel ( );

  QVariant data ( const QModelIndex &f_index, int f_role ) const;  // <-- gibt die Data zurück (Anhand Qt::ItemDataRole)
  bool setData ( const QModelIndex &f_index, const QVariant &f_value, int f_role = Qt::EditRole );  // <-- setzt die Data zurück (Anhand Qt::ItemDataRole)
  Qt::ItemFlags flags ( const QModelIndex &f_index ) const;
  QVariant headerData ( int f_section, Qt::Orientation f_orientation, int f_role = Qt::DisplayRole ) const;
  QModelIndex index ( int f_row, int f_column, const QModelIndex &f_parent = QModelIndex ( ) ) const;
  QModelIndex parent ( const QModelIndex &f_index ) const;
  int rowCount ( const QModelIndex &f_parent = QModelIndex ( ) ) const;
  int columnCount ( const QModelIndex &f_parent = QModelIndex ( ) ) const;

  C_DataItem * RootItem ( );
  const C_DataItem * RootItem ( ) const;
  void RootItem ( C_DataItem *fp_rootItem );

  virtual bool dropMimeData ( const QMimeData *fp_data, Qt::DropAction f_action, int f_row, int f_column, const QModelIndex &f_parent );  // <-- Daten werden auf/neben ein Item gedroppt
  virtual QMimeData* mimeData ( const QModelIndexList &fl_indexes ) const;  // <-- Drag von Items
  virtual QStringList mimeTypes ( ) const;  // <-- siehe Drag&Drop
  Qt::DropActions supportedDropActions ( ) const;

  virtual bool removeRows ( int f_row, int f_amount, const QModelIndex &f_parent = QModelIndex ( ) );  // <-- Entfernen von Items
  virtual bool insertRows ( int f_row, int f_amount, const QModelIndex &f_parent = QModelIndex ( ) );  // <-- Einfügen von Items

private slots:
  void ChangedAItem ( );  // <-- Sollte per connect an ein Signal von C_DataItem gehängt werden, dass ausgestrahlt wird, wenn das C_DataItem geändert wird

private:
  C_DataItem* mp_rootItem;
};
Wenn du noch Fragen hast, oder ein mehr oder weniger kompliziertes Beispiel mit Drag&Drop, Löschen und Hinzufügen von Items usw willst, meld dich bei mir per PM...

Elgrimm Esleborn

PS: Ich hoffe das hilft weiter...