2010-06-08 15 views
7

Używam klasy Qt QGraphicsScene, dodając predefiniowane elementy, takie jak QGraphicsRectItem, QGraphicsLineItem itd. I chcę serializować zawartość sceny na dysku. Jednak podstawowa klasa QGraphicsItem (z której wywodzą się inne elementy) nie obsługuje serializacji, więc muszę przetworzyć własny kod. Problemem jest to, że dostęp do tych obiektów odbywa się za pomocą wskaźnika bazowego QGraphicsItem, więc kod serializacji mam to straszne:Serializacja QGraphicsScene zawartość

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 
    } 
    ... 
} 

To nie jest dobry kod IMHO. Tak więc, zamiast mogę utworzyć klasę ABC takiego:

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 
    } 
    ... 
}; 

mogę następnie dodać Rect obiektów za pomocą QGraphicsScene::addItem(new Rect(,,,));

Ale to naprawdę nie pomaga mi jak dodaje padnie:

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

W jaki sposób mogę to wykonać?

+0

Dlaczego 'myitem-> serialize()' crash.Nie widzę tego? –

Odpowiedz

3

Zgadzam się z innych plakatów , QGraphicsItem może naprawdę być postrzegany jako element widoku, więc oddzielenie danych modelu na własną klasę byłoby prawdopodobnie lepsze.

To powiedziawszy, myślę, że przyczyną awarii jest niewłaściwa obsada.

Jeśli wykonaj następujące czynności:

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); 

Należy zauważyć, że R == qi r == QR, ale r = i!. Jeśli myślisz o tym, jak obiekt, który dziedziczy wiele, jest reprezentowany w pamięci, pierwsza klasa podstawowa jest pierwsza w pamięci, druga klasa podstawowa jest druga i tak dalej. Zatem wskaźnik do drugiej klasy bazowej zostanie przesunięty o [w przybliżeniu] rozmiar pierwszej klasy bazowej.

Tak, aby naprawić swój kod, myślę, że trzeba zrobić coś takiego:

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(...); 
} 

Jest to jeden z wielu powodów, chciałbym uniknąć wielokrotnego dziedziczenia w miarę możliwości. Zdecydowanie zalecamy odgrodzenie danych modelu, zgodnie z wcześniejszym zaleceniem.

1

Serializacja QGraphicsItem nie jest dobrym pomysłem. A QGrahpicsScene ma reprezentować twoje dane. Zamiast serializowania reprezentacji, lepiej serializować dane/model twojej aplikacji.

Jeśli chcesz zarejestrować układ elementów graficznych, możesz użyć niestandardowego QGraphicsItem i narysować w QPicture.

+0

Elementy zawierają wszystko, czego potrzebuję do serializacji, więc w tym przypadku można je uznać za dane/model. – Rob

+0

BTW nie wydaje się wspierać łączenia QGraphicsScene z oddzielnym modelem. – Rob

0

Jeśli naprawdę chcesz do serializacji te elementy tworzyć

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

dla każdego z QGraphicsItem podklasy, które chcesz do serializacji, funkcje te są funkcją non-member. Podejście jest również wyjaśnione w dokumentacji QDataStream

Ale popieram Stephens odpowiedź, może warto rozważyć pociągnięcie rzeczywiste dane z sceny i umieszczenie go w osobnej klasie modelu

+0

To nie zadziała, dopóki nie zacznę przesyłać strumieniowo każdego QGraphicsItems do poprawnego typu. – Rob