PDA

View Full Version : Qlist Serialization by qdatastream error



WezSieTato
4th January 2014, 12:28
Hi,
I try to serialize my own class, which inherits from QGraphicsItem and QObject, but i have a problem when i want to read it from file:


#include "zarzadcaodczytu.h"

#include <QMetaProperty>
#include <QFile>
#include <QMetaType>
#include <qdebug.h>

#include "../editorwindow.h"
#include "ui_editorwindow.h"



ZarzadcaOdczytu::ZarzadcaOdczytu()
{
}

bool ZarzadcaOdczytu::wczytaj(QString nazwaPliku, EditorWindow *edytor)
{
//HBMalyMis and HBDuzyMis inherits from HoneyBearsMapItem
qRegisterMetaType<HBMalyMis>("HBMalyMis");
qRegisterMetaType<HBDuzyMis>("HBDuzyMis");

QFile file(nazwaPliku);
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
QList< HoneyBearsMapItem * > items;

//in debugger i can see that every objects exists and values are set properly
in >> items;
file.close();

delete edytor->ui->graphicsView->scene();

//PlanszaScene inherits from QGraphicsScene
PlanszaScene * nowa = new PlanszaScene(1336, 640, edytor);
edytor->ui->graphicsView->setScene(nowa);


qDebug() << items.count();

for(HoneyBearsMapItem *item : items){
nowa->addItem(item); // <- in this line app crash, when I try to call metaObject() app crash too
}


return true;
}

HoneyBearsMapItem *ZarzadcaOdczytu::create(const char *classname)
{
QString name(classname);

if(name == "HBDuzyMis")
return new HBDuzyMis();
if(name == "HBMalyMis")
return new HBMalyMis();

return NULL;
}

QDataStream &operator>>(QDataStream &in, HoneyBearsMapItem *item)
{
char * className;
in >> className;

item = ZarzadcaOdczytu().create(className);

const QMetaObject *meta = item->metaObject();
int count = meta->propertyCount();
for (int i=0; i<count; ++i) {
QMetaProperty metaproperty = meta->property(i);
if (metaproperty.isWritable()){
const char *name = metaproperty.name();
QVariant value;
in >> value;
item->setProperty(name, value);

//every values are read properly
qDebug() << "Property " << name << " " << value;

}

}


return in;

}


What I'm doing wrong :/ ? In the operator >> function I can call metaObject(), but when I try do this outside this function after it, the application crash. Other objects methods works fine. The main problem is when I try add object to scene :/

anda_skoa
4th January 2014, 14:08
There are all kinds of fishy things. For example who frees className or why does the operator ignore the passed in item?

My recommendation would be to separate serialization from the item.

For example like this



class MyItem : public QGraphicsItem
{
public:
QVariantMap serialize() const;

static MyItem* deserizalize(const QVariantMap &data);
}


Used like this


QDataStream stream(...);
foreach (MyItem* item, items) {
stream << item->serialize();
}



QDataStream stream(...);
while (!stream.atEnd()) {
QVariantMap data;
stream >> data;

items << MyItem::deserialize(data);
}


For the classname I would suggest to either use QByteArray or to have an entry for that in the QVariantMap (but also a QByteArray to avoid manual memory management)

Cheers,
_

deepak_purandare
13th August 2014, 15:38
I found a way to handle this. This may be non standard and need template specialization.
I created a separate header file with the template and included it wherever required. Here it is. In case you need other data structures to be serialized, you may follow the similar pattern.

Cheers !

#ifndef MODSER_H
#define MODSER_H
#include <QDataStream>

template <typename T>
QDataStream& operator>>(QDataStream& s, QList<T*>& l)
{
l.clear();
quint32 c;
s >> c;
l.reserve(c);
for(quint32 i = 0; i < c; ++i)
{
T * t = new T;
s >> t;
l.append(t);
if (s.atEnd())
break;
}
return s;
}

#endif // MODSER_H