Showing posts with label QDialog. Show all posts
Showing posts with label QDialog. 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 :

 
 
     
         
     


Tuesday, August 2, 2011

Save Screenshot of QGraphicsScene

In order to display items that are residing in QGraphicsScene, QGraphicsView is used. In the sample application Custom QDialog contains a QGraphicsView with a QGraphicsScene inside it.

Project Directory Structure in Qt Creator IDE :



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


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


Dialog.h file contains custom QDialog interface.
#ifndef DIALOG_H
#define DIALOG_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_saveSceneAsImage();

private:
    QGraphicsScene* scene;
    QGraphicsView* view;
    QVBoxLayout* layout;
    QPushButton* btnSaveScene;
};
#endif // DIALOG_H


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

#include <QGraphicsView>
#include <QGraphicsScene>
#include <QVBoxLayout>
#include <QPushButton>
#include <QString>
#include <QFileDialog>
#include <QPixmap>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    scene = new QGraphicsScene(this);
    scene->addEllipse(22,3,12,13,QPen(QColor("red")));
    scene->addLine(1,2,8,9,QPen("blue"));
    scene->addRect(12,12,6,7,QPen("green"));
    view = new QGraphicsView(scene,this);
    layout = new QVBoxLayout(this);
    btnSaveScene = new QPushButton("Take Scene SnapShot");
    connect(btnSaveScene, SIGNAL(clicked()), this, SLOT(sl_saveSceneAsImage()));
    layout->addWidget(view);
    layout->addWidget(btnSaveScene);
    setLayout(layout);
    resize(270,200);
}

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

void Dialog::sl_saveSceneAsImage()
{
    QString fileName = QFileDialog::getSaveFileName(this, "Save Scene", "", "Image (*.png)");
    QPixmap pixMap = QPixmap::grabWidget(view);
    pixMap.save(fileName);
    close();
}


QGraphicsScene content can be saved as a png image file. Sample QGraphicsScene contains items of type line,rectangle and ellipse. Taken snapshot displays all these items inside of saved snapshot.

sl_saveSceneAsImage() slot of custom QDialog uses Qpixmap::grabWidget function to create a pixmap and paints the QGraphicsView inside it. Because all the child items are also painted in then QGraphicsScene becomes painted inside snapshot, too.

As a result Qpixmap instance is saved to specified location with :
pixMap.save(fileName);


Sample QGraphicsScene content :




Saved QGraphicsScene Snapshot :



Wednesday, June 8, 2011

Reimplementing closeEvent of QDialog

It is always required to ask the user before closing the dialog whether he/she is sure about that. closeEvent event handler can also be used to save the position of the dialog before it is being closed. closeEvent of QDialog is being called before than the destructor of the extended QDialog instance.
Sample extended QDialog shows a QMessageBox instance when the user clicks on the close button that is placed at the top right corner of the dialog and asks for confirmation before closing the dialog. Depending on the user’s selection, dialog closes or stays open.
Sample project started as a QT Gui Application and contains main.cpp, QDialogCloseEvent.h and QDialogCloseEvent.cpp files.
Project Directory Structure in Qt Creator IDE :

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

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

QDialogCloseEvent.h file is the extended QDialog class header file.
#ifndef QDIALOGCLOSEEVENT_H
#define QDIALOGCLOSEEVENT_H
#include <QDialog>
class Dialog : public QDialog
{
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
protected:
    void closeEvent(QCloseEvent * event);
};
#endif // QDIALOGCLOSEEVENT_H

QDialogCloseEvent.cpp file contains implementation details for extended QDialog class.
#include "QDialogCloseEvent.h"
#include <QMessageBox>
#include <QCloseEvent>
Dialog::Dialog(QWidget *parent) : QDialog(parent)
{
    resize(300,90);
}
Dialog::~Dialog(){}
void Dialog::closeEvent(QCloseEvent *event)
{
    QMessageBox msgBox;
    msgBox.setText("Are you sure you want to close?");
    msgBox.setStandardButtons(QMessageBox::Close | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Close);
    int result = msgBox.exec();
    switch (result) {
      case QMessageBox::Close:
          event->accept();
          break;
      case QMessageBox::Cancel:
          event->ignore();
          break;
      default:
          QDialog::closeEvent(event);
          break;
    }
}

Custom QDialog with QMessageBox:

Application created by QT Creator and uses Qt4.7 .

Sunday, May 8, 2011

Create Custom QDialogs With QLayout Classes

Qt Designer is used to design user interfaces for QT applications. In addition to using QT Designer to generate user interfaces, you can populate your dialogs with widgets on them dynamically at runtime by using layout classes. To achieve this, you need to extend qdialog class and add widgets to your derived qdialog instance dynamically at runtime.
Qt's layout classes are used to place widgets on parent dialogs or widgets. Instead of manually placing widgets on main containers and creating static user interfaces, layout classes help to place widgets easily. There are different QT layout classes but QHBoxLayout and QVBoxLayout are the most popular of them. By using the addWidget() method of layout class, you place items on the layout. After adding widgets to the layout properly, it is required to call setLayout() method of the main container to make layout visible on it.
Sample project started as a QT Gui Application and contains main.cpp, DynamicQDialog.h and DynamicQDialog.cpp files.
DynamicDialog.pro is the project configuration file contains:
TARGET = DynamicDialog
CONFIG   += qt gui
TEMPLATE = app
SOURCES += main.cpp \
    DynamicQDialog.cpp
HEADERS += \
    DynamicQDialog.h

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

DynamicQDialog.h file is the derived QDialog class header file. Custom QDialog contains signals and slots to be associated with buttons on the dialog.
#ifndef DYNAMICQDIALOG_H
#define DYNAMICQDIALOG_H
#include <QDialog>
class DynamicQDialog : public QDialog
{
    Q_OBJECT
public:
    DynamicQDialog(QWidget * parent = 0, Qt::WindowFlags f = 0);
    ~DynamicQDialog();
public slots:
    void sl_accept();
    void sl_cancel();
signals:
};
#endif // DYNAMICQDIALOG_H

DynamicQDialog.cpp file contains implementation details for derived QDialog class. 2 QPushButtons added to the QHBoxLayout dynamically at runtime and displayed on the DynamicQDialog instance.
#include "DynamicQDialog.h"
#include <QHBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QMessageBox>

DynamicQDialog::DynamicQDialog(QWidget* parent, Qt::WindowFlags flags): QDialog( parent, flags )
{
    QGridLayout* mainGrid = new QGridLayout;
    QVBoxLayout* topLayout = new QVBoxLayout;
    topLayout->addWidget(new QTextEdit);
    mainGrid->addLayout(topLayout,0,0);

    QHBoxLayout* hLayout = new QHBoxLayout;
    QPushButton* btn;
    for( int i=0; i<2 br="" i="">        if( i == 0 ) {
            btn = new QPushButton("OK");
            connect(btn, SIGNAL(clicked()), this, SLOT(sl_accept()));
        }
        else if( i == 1 ) {
            btn = new QPushButton("Cancel");
            connect(btn, SIGNAL(clicked()), this, SLOT(sl_cancel()));
        }
        hLayout->addWidget(btn);
    }
    mainGrid->addLayout(hLayout,1,0);

    setLayout(mainGrid);
}

DynamicQDialog::~DynamicQDialog(){}

void DynamicQDialog::sl_accept(){
    QMessageBox msgBox;
    msgBox.setText("OK Clicked!");
    msgBox.exec();
}

void DynamicQDialog::sl_cancel(){
    QMessageBox msgBox;
    msgBox.setText("Cancel Clicked!");
    msgBox.exec();
}



Application created by QT Creator and uses Qt4.7 .