Showing posts with label QGraphicsItem. Show all posts
Showing posts with label QGraphicsItem. Show all posts

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 :

 
 
     
         
     


Wednesday, July 27, 2011

Load QGraphicsScene From QDataStream

Qt allows you to read binary data from files into QDataStream. In this sample serialized QGprahicsItem is created on the QGraphicsScene by reading related data from a text file.
Sample project started as a QT Gui Application and contains main.cpp, LoadSceneFromQDataStream.h, LoadSceneFromQDataStream.cpp, MyGraphicsItem.h and MyGraphicsItem.cpp files.
Project Directory Structure in Qt Creator IDE :


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

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

LoadSceneFromQDataStream.h file contains custom QDialog which displays content of binary file in a QGraphicsScene instance.
#ifndef LOADSCENEFROMQDATASTREAM_H
#define LOADSCENEFROMQDATASTREAM_H
#include <QDialog>

class QGraphicsScene;
class QGraphicsView;
class QVBoxLayout;

class Dialog : public QDialog
{
    Q_OBJECT

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

public slots:
    void sl_loadSceneFromFile();

private:
    QGraphicsScene* scene;
    QGraphicsView* view;
    QVBoxLayout* layout;
    QPushButton* btnLoad;
};

#endif // LOADSCENEFROMQDATASTREAM_H

LoadSceneFromQDataStream.cpp file contains implementation details for the custom QDialog.
#include "LoadSceneFromQDataStream.h"
#include "MyGraphicsItem.h"

#include <QVBoxLayout>
#include <QPushButton>
#include <QGraphicsView>
#include <QFile>
#include <QMessageBox>
#include <QDir>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    scene = new QGraphicsScene(this);
    view = new QGraphicsView(scene,this);
    layout = new QVBoxLayout(this);
    layout->addWidget(view);
    btnLoad = new QPushButton("Load Scene From File");
    connect(btnLoad, SIGNAL(clicked()), this, SLOT(sl_loadSceneFromFile()));
    layout->addWidget(btnLoad);
    setLayout(layout);
    resize(270,200);
}

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

void Dialog::sl_loadSceneFromFile()
{
    QString fileName(QDir::currentPath().append("/sceneData.txt"));
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly))
    {
            return;
    }
    QDataStream in(&file);
    int itemListSize;
    in >> itemListSize;
    for( int i = 0; i< itemListSize; i++ )
    {
        qreal xCoord = 0;
        qreal yCoord = 0;
        in >> xCoord;
        in >> yCoord;
        MyGraphicsItem* item = new MyGraphicsItem();
        item->setPos(xCoord,yCoord);
        scene->addItem(item);
    }
    QMessageBox::warning(this,"Success","Loaded Scene Items From File");
    close();
}

sl_loadSceneFromFile() opens sceneData.txt file and reads its content into QDataStream instance.
sceneData.txt file is located under LoadSceneFromQDataStream/LoadSceneFromQDataStream folder of the project. sceneData.txt file is created by the previous sample application.

First serialized data to the sceneData.txt file is the number of QGraphicsItems on the QGraphicsScene. It is read into the variable “itemListSize” from sceneData.txt file. Then for each QGraphicsItem on the QGraphicsScene, xCoordinate and yCoordinate of the QGraphicsItem is stored in the file in binary format. By reading x and y coordinate of the QGraphicsItem from sceneData.txt file, item’s position is set. After setting the pos of the QGraphicsItem, it is inserted into the list of QGraphicsItems on the QGraphicsScene by calling the addItem function of QGraphicsScene.

Regenerated QGraphicsItem instance on the QGraphicsScene is a custom/derived QGprahicsItem and is defined in MyGraphicsItem.h file.
#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

Custom QGraphicsItem contains constructor, destructor, boundingRect() and paint() methods.

MyGraphicsItem.cpp file contains implementation details for the 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);
}


When you run the application, a dialog with a "load scene from file" button is displayed.By clicking the qpushbutton, application searches for the sceneData.txt file and loads files content into the QGraphicsScene.



Tuesday, June 21, 2011

Serialize QGraphicsScene Binary Data By Using QDataStream

QGraphicsScene class enables easy management of QGraphicsItem instances in a 2D environment. QGraphicsScene acts as a container for custom QGraphicsItems.
Custom QDialog with a QGraphicsView helps to visualize QGraphicsItems that are included in a QGraphicsScene. By using addItem() function of QGraphicsScene, custom QGraphicsItems can be added to the QGraphicsScene instance. QGprahicsItem binary data such as x() and y() coordinates can be serialized to a QFile by using QDataStream.
Sample project started as a QT Gui Application and contains main.cpp, SceneToDataStream.h, SceneToDataStream.cpp, MyGraphicsItem.h and MyGraphicsItem.cpp files.
Project Directory Structure in Qt Creator IDE :

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

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

SceneToDataStream.h file is the extended QDialog class header file.
#ifndef SCENETODATASTREAM_H
#define SCENETODATASTREAM_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_saveSceneToFile();

private:
    QGraphicsScene* scene;
    MyGraphicsItem* item;
    QGraphicsView* view;
    QVBoxLayout* layout;
    QPushButton* btnSave;
};

#endif // SCENETODATASTREAM_H

SceneToDataStream.cpp file contains implementation details for extended QDialog class.
#include "SceneToDataStream.h"
#include "MyGraphicsItem.h"

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFile>
#include <QList>
#include <QMessageBox>
#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);
    btnSave = new QPushButton("Save Scene To File");
    connect(btnSave, SIGNAL(clicked()), this, SLOT(sl_saveSceneToFile()));
    layout->addWidget(btnSave);
    setLayout(layout);
    resize(270,200);
}

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

void Dialog::sl_saveSceneToFile()
{
    QString fileName = QDir::currentPath().append("/sceneData.txt");
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly))
    {
            return;
    }
    QDataStream out(&file);
    QList<QGraphicsItem*> itemList = scene->items();
    int itemListSize = itemList.size();
    out << itemListSize;
    foreach( QGraphicsItem* item, itemList)
    {
        out << item->x();
        out << item->y();
    }
    QMessageBox::warning(this,"Success","Saved Scene Data to File");
    close();
}

sl_saveSceneToFile() slot of Dialog class is connected to QPushButton clicked signal and serializes number of all the items on the scene with item x() and y() coordinates respectively.

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

sceneData.txt is the produced file that contains serialized binary data.

Tuesday, October 19, 2010

Type of Custom QGraphicsItem on the QGraphicsScene

Applications that contain different kinds of derived QGraphicsItem instances need to identify that instances to achieve different operations on them at runtime.
"int QGraphicsItem::type() const [virtual]" method of QGraphicsItem class enables the clients to check for the type of the custom QGraphicsItem. Each unique QGraphicsItem instance returns a unique integer value from the type() method.
For custom QGraphicsItem classes it is also required to implement
"QRectF QGraphicsItem::boundingRect(void) const"
and
"void QGraphicsItem::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)"
methods additionally.

"CustomGraphicsItems.h" file contains TextItem and LineItem class definitions.
#include <QGraphicsItem>
class TextItem : public QGraphicsItem {
public:
 enum { Type = UserType + 1 };
 int type() const { return Type; }
 TextItem(QGraphicsItem* parent = 0 );
 ~TextItem();
protected:
 void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 );
 QRectF boundingRect() const;
};
class LineItem : public QGraphicsItem {
public:
 enum { Type = UserType + 2 };
 int type() const { return Type; }
 LineItem(QGraphicsItem* parent = 0);
 ~LineItem();
protected:
 void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 );
 QRectF boundingRect() const;
};

Each custom QGraphicsItem instance is uniquely identified in the enum .

"CustomGraphicsItems.cpp" file contains implementation for TextItem and LineItem classes.

#include "CustomGraphicsItems.h"
TextItem ::TextItem(QGraphicsItem* parent) : QGraphicsItem(parent) {}
TextItem::~TextItem() {}
QRectF TextItem::boundingRect() const {
 return QRectF();
}
void TextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {}
LineItem ::LineItem(QGraphicsItem* parent) : QGraphicsItem(parent) {}
LineItem::~LineItem() {}
void LineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {}
QRectF LineItem::boundingRect() const {
 return QRectF();
}

"CustomScene.h" file contains derived QGraphicsScene class.
#include <QGraphicsScene>
class CustomScene : public QGraphicsScene {
public :
 CustomScene(QObject * parent = 0);
 ~CustomScene();
};

"CustomScene.cpp" file contains implementation for derived QGraphicsScene class.
#include "CustomScene.h"
CustomScene::CustomScene(QObject * parent) : QGraphicsScene(parent) {}
CustomScene::~CustomScene() {}

"CustomMainWindow.h" file contains definition for derived QMainWindow class.
#include <QMainWindow>
class CustomScene;
class CustomMainWindow : public QMainWindow {
public:
 CustomMainWindow(QWidget *parent = 0);
 ~CustomMainWindow();
 void displayItemType();
 void addItemsToGraphicsScene();
private:
 CustomScene* customScene;
};

"CustomMainWindow.cpp" file contains implementation for derived QMainWindow class.
#include <QDebug>
#include "CustomMainWindow.h"
#include "CustomScene.h"
#include "CustomGraphicsItems.h"
CustomMainWindow :: CustomMainWindow(QWidget *parent) {
 customScene = new CustomScene(this);
 addItemsToGraphicsScene();
 displayItemType();
}
void CustomMainWindow :: addItemsToGraphicsScene() { 
 TextItem* textItem = new TextItem();
 customScene->addItem(textItem);
 LineItem* lineItem = new LineItem();
 customScene->addItem(lineItem);
}
void CustomMainWindow :: displayItemType() {
 QList<QGraphicsItem*> itemList = customScene->items();
 for(int i=0; i<itemList.size(); i++){
  if(itemList[i]->type() == TextItem::Type )
   qDebug() << "I am TextItem";
  else if(itemList[i]->type() == LineItem::Type)
   qDebug() << "I am LineItem";
 }
}
CustomMainWindow :: ~CustomMainWindow() {}

"Main.cpp" file contains an instance of CustomMainWindow class. CustomScene is the container for the TextItem and LineItem instances and it is initialized in the CustomMainWindow constructor. addItemsToGraphicsScene() method of CustomMainWindow adds TextItem and LineItem instances to the CustomScene.
Types of custom QGraphicsItem instances are checked in displayItemType() method of CustomMainWindow class.
#include <QApplication>
#include "CustomMainWindow.h"
int main(int argc, char *argv[])
{
 QApplication app(argc, argv);
  CustomMainWindow* cm = new CustomMainWindow;
  delete cm;
 return app.exec();
}


Tested with MSVS2008 and QT4.6.0