Wednesday, August 3, 2011

Save QGraphicsScene to XML File By Using QXmlStreamWriter

QGraphicsItems that are residing in a QGraphicsScene can be saved to XML file by using QXMLStreamWriter class.
Sample project started as a QT Gui Application and contains main.cpp, SaveQGraphicsSceneToXML.h, SaveQGraphicsSceneToXML.cpp, MyGraphicsItem.h and MyGraphicsItem.cpp files.
Project Directory Structure in Qt Creator IDE :



SaveQGraphicsSceneToXML.pro is the project configuration file and contains:
QT       += core gui
TARGET = SaveQGraphicsSceneToXML
TEMPLATE = app
SOURCES += main.cpp\
        SaveQGraphicsSceneToXML.cpp\
        MyGraphicsItem.cpp
HEADERS  += SaveQGraphicsSceneToXML.h\
            MyGraphicsItem.h

main.cpp file contains the custom QDialog instance and shows it.
#include <QApplication>
#include "SaveQGraphicsSceneToXML.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();
    return a.exec();
}

MyGraphicsItem is a derived custom QGraphicsItem class that implements boundingRect() and paint() functions of the parent. MyGraphicsItem is a rectangular derived QGraphicsItem and added to the QGraphicsScene.
MyGraphicsItem.h file contains custom QGraphicsItem class declaration.
#ifndef MYGRAPHICSITEM_H
#define MYGRAPHICSITEM_H
#include <QGraphicsItem>
class MyGraphicsItem : public QGraphicsItem
{
public:
    MyGraphicsItem(QGraphicsItem *parent = 0, QGraphicsScene *scene = 0);
    ~MyGraphicsItem();

protected:
    QRectF boundingRect() const;

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget);
};
#endif // MYGRAPHICSITEM_H

MyGraphicsItem.cpp file contains implementation details for custom QGraphicsItem class.
#include "MyGraphicsItem.h"
#include <QPainter>
MyGraphicsItem::MyGraphicsItem(QGraphicsItem* parent, QGraphicsScene* scene) : QGraphicsItem(parent,scene)
{
}

MyGraphicsItem::~MyGraphicsItem(){}

QRectF MyGraphicsItem::boundingRect() const
{
    qreal penWidth = 1;
    return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
                  20 + penWidth, 20 + penWidth);
}

void MyGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
           QWidget *widget)
{
    Q_UNUSED(widget)
    Q_UNUSED(option)

    QPen pen;
    pen.setWidthF(2);
    pen.setStyle(Qt::DashLine);
    painter->setPen(pen);
    painter->setBrush(QBrush(QColor(50,120,80)));
    painter->drawRoundedRect(boundingRect(), 25, 25, Qt::RelativeSize);
}

SaveQGraphicsSceneToXML.h is derived from QDialog class which contains QGraphicsView in it.
#ifndef SAVEQGRAPHICSSCENETOXML_H
#define SAVEQGRAPHICSSCENETOXML_H
#include <QDialog>

class QGraphicsScene;
class MyGraphicsItem;
class QGraphicsView;
class QVBoxLayout;

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

public slots:
    void sl_saveSceneToXML();

private:
    QGraphicsScene* scene;
    MyGraphicsItem* item;
    QGraphicsView* view;
    QVBoxLayout* layout;
    QPushButton* btnSaveToXML;
};
#endif // SAVEQGRAPHICSSCENETOXML_H

SaveQGraphicsSceneToXML.cpp contains implementation details for derived QDialog class.
#include "SaveQGraphicsSceneToXML.h"
#include "MyGraphicsItem.h"

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFile>
#include <QList>
#include <QMessageBox>
#include <QXmlStreamWriter>
#include <QDir>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    scene = new QGraphicsScene(this);
    item = new MyGraphicsItem();
    item->setPos(34,35);
    scene->addItem(item);
    view = new QGraphicsView(scene,this);
    layout = new QVBoxLayout(this);
    layout->addWidget(view);
    btnSaveToXML = new QPushButton("Save Scene To XML");
    connect(btnSaveToXML, SIGNAL(clicked()), this, SLOT(sl_saveSceneToXML()));
    layout->addWidget(btnSaveToXML);
    setLayout(layout);
    resize(270,200);
}

Dialog::~Dialog()
{
    delete btnSaveToXML;
    delete item;
    delete scene;
    delete view;
    delete layout;
}

void Dialog::sl_saveSceneToXML()
{
    QString fileName(QDir::currentPath().append("//sceneData.xml"));
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly))
    {
            return;
    }
    QXmlStreamWriter xmlWriter(&file);
    xmlWriter.setAutoFormatting(true);
    xmlWriter.writeStartDocument();
    xmlWriter.writeStartElement("SceneData");
    xmlWriter.writeAttribute("version", "v1.0");
    xmlWriter.writeStartElement("GraphicsItemList");
    foreach( QGraphicsItem* item, scene->items())
    {
        if( item->type() == MyGraphicsItem::Type )
        {
            MyGraphicsItem* myItem = (MyGraphicsItem*)item;
            xmlWriter.writeStartElement("MyGraphicsItem");
            xmlWriter.writeAttribute("xCoord", QString::number(myItem->x()));
            xmlWriter.writeAttribute("yCoord", QString::number(myItem->y()));
            xmlWriter.writeEndElement();  //end of MyGraphicsItem
        }
    }
    xmlWriter.writeEndElement();   //end of GraphicsItemList
    xmlWriter.writeEndElement();   //end of SceneData
    QMessageBox::warning(this,"Success","Saved Scene Data to XML File");
    close();
}

QGraphicsScene contains custom QGraphicsItem in it. Derived QGraphicsItem position is set and then added onto the QGraphicsScene. Different QGraphicsItems can be added onto the QGraphicsScene, too.

btnSaveToXML QPushButton is connected to sl_saveSceneToXML slot of current Dialog instance. By clicking on the QPushButton instance which has a text property set to "Save Scene To XML" sl_saveSceneToXML slot is called.

sl_saveSceneToXML slot saves the content of QGraphicsScene into the sceneData.xml file. QxmlStreamWriter is used to write data into the opened file.

xmlWriter.writeStartDocument(); line writes a document which starts with XML version number "1.0" and also writes the encoding "UTF-8" information.

xmlWriter.writeStartElement("SceneData"); line writes the start element with “SceneData”.

xmlWriter.writeAttribute("version", "v1.0"); line adds “version” attribute with “v1.0” value to “SceneData” element.

xmlWriter.writeStartElement("GraphicsItemList"); line writes "GraphicsItemList" under “SceneData” element.

Foreach custom QGraphicsItem instance that is residing in the QGraphicsScene a new element is inserted into the xml file with writeStartElement("MyGraphicsItem") function of QXmlStreamWriter. Previously setted xCoord and yCoord attributes of custom QGraphicsItem are written into the xml file with writeAttribute("yCoord", Qstring::number(myItem->y())); function of QxmlStreamWriter.
Foreach writeStartElement() function, corresponding writeEndElement() function is called to close the previous start element. Each QGraphicsItem instance is identified by its item->type() and written into the XML file.

“GraphicsItemList” and “SceneData” elements are closed by calling xmlWriter.writeEndElement(); .

Saved XML file content is :

 
 
     
         
     


2 comments:

  1. Agraphic scene saved as in xml format in qraphicscene,nice to sharing this posting.blog hosting review

    ReplyDelete
  2. I wanted to save my scene and reload it at a latter time when the application starts .This post really helped.Thanks.

    ReplyDelete