при этом проще добавить в наследники итемов методы загруски и сохранения.
как я делал:
для базового класса, который наследуется от graphicsITem добавил 2 виртуальных метода loadFromStream и saveToStream, которые отвеяают за загрузку и сохранение item в поток(но я на самом деле храню в XML-дереве).
такой подход позволяет расширять возможности загрузки/сохранения в наследниках.
вот пример базового класса для элементов (для виджетов на сцене у меня свой класс, но суть таже)
class QRailItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES (QGraphicsItem)
public:
virtual void loadFromStream(QDomDocument * doc,QDomElement * node);
virtual void saveToStream(QDomDocument * doc,QDomElement * node);
};
вот реализация
void QRailItem::loadFromStream(QDomDocument * /*doc*/, QDomElement * node)
{
QDomElement railItemNode = node->firstChildElement("RailItemData"); //нода класса QRailItem
if(!railItemNode.isNull())
{
bool ok;
QPointF pos;
id = railItemNode.attribute("ObjectID","0").toLong(&ok);
setRotation(railItemNode.attribute("Angle").toFloat(&ok));
pos.setX(railItemNode.attribute("PosX").toFloat(&ok));
pos.setY(railItemNode.attribute("PosY").toFloat(&ok));
this->setPos(pos);
setZValue(railItemNode.attribute("ZValue","0").toFloat(&ok));
}
}
void QRailItem::saveToStream(QDomDocument * doc, QDomElement * node)
{
QDomElement railItemNode = doc->createElement("RailItemData"); //создаю ноду класса QRailItem
railItemNode.setAttribute("ObjectID",id);
railItemNode.setAttribute("PosX",pos().x());
railItemNode.setAttribute("PosY",pos().y());
railItemNode.setAttribute("Angle",rotation());
railItemNode.setAttribute("ZValue",zValue());
node->appendChild(railItemNode);
}
теперь пример наследника
class QSection: public QRailItem
{
Q_OBJECT
public:
void loadFromStream(QDomDocument * doc,QDomElement * node);
void saveToStream(QDomDocument * doc,QDomElement * node);
};
сохраняем наследника
void QSection::loadFromStream(QDomDocument * doc,QDomElement * node)
{
QRailItem::loadFromStream(doc,node); //загрузка части предка
QDomElement sectionNode = node->firstChildElement("SimpleSectionData"); //находим часть этого класса
if(!sectionNode.isNull()) //далее все грузится все что касается этого класса, так как размер, позицию и прочее мы узнали при загрузке базового класса
{
QDomElement anchorsNode = sectionNode.firstChildElement("Anchors");
if(!anchorsNode.isNull())
for(QDomNode anchorNode = anchorsNode.firstChildElement("Anchor");!anchorNode.isNull();anchorNode = anchorNode.nextSibling())
{
QDomElement anchorElement = anchorNode.toElement();
if(!anchorElement.isNull())
{
bool ok;
QPointF currentAnchor;
currentAnchor.setX(anchorElement.attribute("PosX").toFloat(&ok));
currentAnchor.setY(anchorElement.attribute("PosY").toFloat(&ok));
fpolygon.addPoint(currentAnchor);
}
}
}
}
void QSection::saveToStream(QDomDocument * doc,QDomElement * node)
{
QRailItem::saveToStream(doc,node); //сохраняем часть базового класса
QDomElement sectionNode = doc->createElement("SimpleSectionData"); //теперь все что связано с этим классом
//получаем список опорных точек полигона секции
QList<QPointF>* anchors_list = fpolygon.anchors();
QPointF current_acnchor;
QDomElement anchors = doc->createElement("Anchors");
for(QList<QPointF>::iterator current_anchor_it=anchors_list->begin();current_anchor_it!=anchors_list->end();current_anchor_it++)
{
current_acnchor = *current_anchor_it;
QDomElement anchor = doc->createElement("Anchor");
anchor.setAttribute("PosX",current_acnchor.x());
anchor.setAttribute("PosY",current_acnchor.y());
anchors.appendChild(anchor);
}
sectionNode.appendChild(anchors);
node->appendChild(sectionNode);
}
а вот кусок как грузить сцену:
//находим секцию с эелементами поля
QDomElement fieldObjects = root.firstChildElement("FieldObjects");
if(fieldObjects.isNull()) return false;
scene()->setLastId(fieldObjects.attribute("LastId","0").toLong(&ok));
for(QDomNode fieldNode = fieldObjects.firstChildElement("FieldObject");!fieldNode.isNull();fieldNode = fieldNode.nextSibling())
{
QDomElement fieldObject = fieldNode.toElement();
if(fieldObject.isNull()) continue;
object_type = fieldObject.attribute("ObjectType");
//тут грузятся много разных объектов разных классов
//****
//находим наш объект
if(object_type=="Section")
{
QSection * section = new QSection(false); //создаем объект
section->loadFromStream(&doc,&fieldObject); //грузим ноду объекта
section->recalculate(); //внутренние пересчеты
fscene->addSection(section); //добавляем на сцену
continue; //дальше нет смысла идти, ищем следующий объект ...
}
//***
}
пример сохранения
//теперь сохраняем данные о графических объектах
QDomElement fieldObjects = doc.createElement("FieldObjects");
fieldObjects.setAttribute("LastId",scene()->lastId());
root.appendChild(fieldObjects);
for(QList<QGraphicsItem*>::iterator items_it = fitems.begin();items_it!=fitems.end();items_it++) //проходимся по всей сцене
{
gi = *items_it;
if((item = dynamic_cast<QRailItem*>(gi))==NULL) continue; //если не наследник от QRailItem проходим далее
//пишем новую секцию <FieldObject>
object_type = item->type();
switch(object_type)
{
case otRailItem:
param = "RailItem";
break;
//****
case otSection:
param = "Section";
break;
//****
default: //остальные игнорируем
continue;
}
QDomElement fieldObject = doc.createElement("FieldObject"); //создаем ноду объекта сцены
fieldObject.setAttribute("ObjectType",param); //пишем тип объекта
switch(object_type)
{
//***
case otSection:
{
if((section = dynamic_cast<QSection*>(item))!=NULL)
section->saveToStream(&doc,&fieldObject);
}
break;
//****
default:
break;
}
//завершаем секцию <FiledObject>
fieldObjects.appendChild(fieldObject);
}
надеюсь идею поняли. по сути это можно грубо назвать сериализацией, но более примитивная и сохраняю/гружу только выбранные поля объектов.