2010-06-08 7 views
7

J'utilise la classe Qt QGraphicsScene, en ajoutant des éléments prédéfinis tels que QGraphicsRectItem, QGraphicsLineItem, etc. et je souhaite sérialiser le contenu de la scène sur le disque. Cependant, la classe de base QGraphicsItem (que les autres éléments que j'utilise) ne supporte pas la sérialisation, donc j'ai besoin de rouler mon propre code. Le problème est que tous les accès à ces objets se fait par un pointeur de base QGraphicsItem, de sorte que le code de sérialisation j'est horrible:Sérialisation du contenu de QGraphicsScene

QGraphicsScene* scene = new QGraphicsScene; 
scene->addRect(QRectF(0, 0, 100, 100)); 
scene->addLine(QLineF(0, 0, 100, 100)); 
... 
QList<QGraphicsItem*> list = scene->items(); 
foreach (QGraphicsItem* item, items) 
{ 
    if (item->type() == QGraphicsRectItem::Type) 
    { 
    QGraphicsRectItem* rect = qgraphicsitem_cast<QGraphicsRectItem*>(item); 
    // Access QGraphicsRectItem members here 
    } 
    else if (item->type() == QGraphicsLineItem::Type) 
    { 
    QGraphicsLineItem* line = qgraphicsitem_cast<QGraphicsLineItem*>(item); 
    // Access QGraphicsLineItem members here 
    } 
    ... 
} 

Ce n'est pas bon à mon humble avis de code. Ainsi, au lieu que je pourrais créer un comme cette classe ABC:

class Item 
{ 
public: 
    virtual void serialize(QDataStream& strm, int version) = 0; 
}; 

class Rect : public QGraphicsRectItem, public Item 
{ 
public: 
    void serialize(QDataStream& strm, int version) 
    { 
    // Serialize this object 
    } 
    ... 
}; 

Je peux alors ajouter des objets à l'aide Rect QGraphicsScene::addItem(new Rect(,,,));

Mais cela ne me permet pas vraiment comme nous allons planter:

QList<QGraphicsItem*> list = scene->items(); 
foreach (QGraphicsItem* item, items) 
{ 
    Item* myitem = reinterpret_class<Item*>(item); 
    myitem->serialize(...) // FAIL 
} 

De toute façon je peux faire ce travail?

+0

Pourquoi 'myitem-> serialize()' plante-t-il?Je ne le vois pas? –

Répondre

3

Je suis d'accord avec les autres affiches , le QGraphicsItem pourrait vraiment être vu comme un élément de vue et donc séparer les données de votre modèle dans sa propre classe serait probablement mieux.

Cela dit, je pense que votre plantage est causé par une distribution inappropriée.

Si vous effectuez les opérations suivantes:

Rect *r = new Rect(); 
QGraphicsItem *qi = reinterpret_cast<QGraphicsItem*>(r); 
QGraphicsRectItem *qr = reinterpret_cast<QGraphicsRectItem*>(r); 
Item *i = reinterpret_cast<Item*>(r); 
qDebug("r = %p, qi = %p, qr = %p, i = %p", r, qi, qr, i); 

Vous devriez voir que r == qi, r == qr, mais r = i!. Si vous pensez à la façon dont un objet qui hérite est représenté en mémoire, la première classe de base est la première en mémoire, la deuxième classe de base est la seconde, et ainsi de suite. Ainsi, le pointeur vers la deuxième classe de base sera compensé par [approximativement] la taille de la première classe de base.

Donc, pour corriger votre code, je pense que vous devez faire quelque chose comme:

QList<QGraphicsItem*> list = scene->items(); 
foreach (QGraphicsItem* item, items) 
{ 
    Rect* myrect = reinterpret_class<Rect*>(item); // needed to figure out the offset to the Item part 
    Item* myitem = reinterpret_class<Item*>(myrect); 
    myitem->serialize(...); 
} 

Ceci est l'une des nombreuses raisons, je voudrais éviter l'héritage multiple lorsque cela est possible. Je vous recommande fortement de séparer les données de votre modèle, comme recommandé précédemment.

1

Sérialiser QGraphicsItem n'est pas une bonne idée. Un QGrahpicsScene est censé représenter vos données. Au lieu de sérialiser la représentation, il est préférable de sérialiser les données/le modèle de votre application.

Si vous souhaitez enregistrer l'arrangement des entités graphiques, peut-être vous pouvez utiliser un QGraphicsItem personnalisé et dessiner dans un QPicture.

+0

Les éléments contiennent tout ce dont j'ai besoin pour sérialiser, donc peuvent être considérés comme les données/le modèle dans ce cas. – Rob

+0

BTW il ne semble pas y avoir de support pour lier un QGraphicsScene à un modèle séparé. – Rob

0

Si vous voulez vraiment sérialiser ces articles créent

QDataStream &operator<<(QDataStream &, const AppropriateSubclass&); 
QDataStream &operator>>(QDataStream &, AppropriateSubclass&); 

pour chacun des sous-classes QGraphicsItem que vous souhaitez sérialiser, ces fonctions sont fonction non-membre. L'approche est également expliquée dans la documentation QDataStream

Mais je soutiens réponse de stephens, vous voudrez peut-être envisager de tirer les données réelles de la scène et de le mettre dans une classe de modèle distinct

+0

Cela ne fonctionne pas, sauf si je jette chaque QGraphicsItems au type correct avant d'essayer de le diffuser. – Rob

Questions connexes