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.

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 .

Tuesday, June 7, 2011

Show QImage in a QLabel

QImage enables to construct images from file paths on the disk. Constructed QImages can be displayed in a QLabel. By setting the pixmap value of QLabel from setPixmap function, QLabel displays content of QImage.
Sample project started as a QT Gui Application and contains main.cpp, ShowQImageDialog.h and ShowQImageDialog.cpp files.
ShowQImageDialog constructor creates a QGridLayout instance that is containing a QScrollArea inside it and displays the image in this area.
Project Directory Structure in Qt Creator IDE :


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

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

ShowQImageDialog.h file is the extended QDialog class header file.
#ifndef SHOWQIMAGEDIALOG_H
#define SHOWQIMAGEDIALOG_H
#include <QDialog>
#include <QGridLayout>
#include <QScrollArea>
#include <QLabel>
#include <QImage>

class ShowQImageDialog : public QDialog
{
    Q_OBJECT

public:
    ShowQImageDialog(QWidget *parent = 0);
    ~ShowQImageDialog();
private:
    QGridLayout* gridLayout;
    QImage* inputImg;
    QLabel* imgDisplayLabel;
    QScrollArea* scrollArea;
};

#endif // SHOWQIMAGEDIALOG_H

ShowQImageDialog.cpp file contains implementation details for extended QDialog class.
#include "ShowQImageDialog.h"
ShowQImageDialog::ShowQImageDialog(QWidget *parent) : QDialog(parent)
{
    gridLayout = new QGridLayout();
    inputImg = new QImage("/home/tufan/wallpaper.png");
    imgDisplayLabel = new QLabel("");
    imgDisplayLabel->setPixmap(QPixmap::fromImage(*inputImg));
    imgDisplayLabel->adjustSize();
    scrollArea = new QScrollArea();
    scrollArea->setWidget(imgDisplayLabel);
    scrollArea->setMinimumSize(256,256);
    scrollArea->setMaximumSize(512,512);
    gridLayout->addWidget(scrollArea,0,0);
    setLayout(gridLayout);
}

ShowQImageDialog::~ShowQImageDialog()
{
    delete inputImg;
    delete imgDisplayLabel;
    delete scrollArea;
    delete gridLayout;
}

ShowQImageDialog:

Application created by QT Creator and uses Qt4.7 .

Check for valid file extension provided by QFileDialog

QFileDialog is used to select files from a specific directory. getOpenFileName() static function of QFileDialog returns the name of the selected file. Also, a filter can be set for the type of the file selected by the user by separating types with ';;'.
Ex:
"All Files (*.*);;JPEG (*.jpeg *.jpg);;PNG (*.png)"
In order to check for file extension of a file name provided by BrowseDialog which is extending QDialog and containing QFileDialog in its sl_browseImage() slot,
bool isValidImageFile(const QString& str)
function is implemented.
isValidImageFile function takes the full path of the file and splits it into pieces to find the file extension from the original QString instance.
File extension is placed after the last period character, so the last member of the QStringList contains the file extension that we are looking for.
By getting the upper case of the file extension which is provided by the client, we can search for a suitable match in our accepted file extension list. If the provided file extension is not in our list, then the derived custom QDialog opens a QMessageBox and gives a warning to the client.
Sample project started as a QT Gui Application and contains main.cpp, BrowseFileDialog.h and BrowseFileDialog.cpp files.

Project Directory Structure in Qt Creator IDE :

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

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

BrowseFileDialog.h file is the derived QDialog class header file. Custom QDialog contains signals and slots to be associated with buttons on the dialog.
#ifndef BROWSEFILEDIALOG_H
#define BROWSEFILEDIALOG_H
#include <QDialog>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>

class BrowseFileDialog : public QDialog
{
    Q_OBJECT
public:
    BrowseFileDialog(QWidget *parent = 0);
    ~BrowseFileDialog();
public slots:
    void sl_browseImage();
private:
    void initLayout();
    void initConnections();
    bool isValidImageFile(const QString& str);
    QLabel* label;
    QLineEdit* lineEdit;
    QPushButton* pushButtonBrowse;
    QPushButton* pushButtonOK;
    QPushButton* pushButtonCancel;
};
#endif // BROWSEFILEDIALOG_H

BrowseFileDialog.cpp file contains implementation details for extended QDialog class.
#include "BrowseFileDialog.h"
#include <QHBoxLayout>
#include <QFileDialog>
#include <QString>
#include <QMessageBox>
#include <QSpacerItem>
BrowseFileDialog::BrowseFileDialog(QWidget *parent) : QDialog(parent)
{
    initLayout();
    initConnections();
}

BrowseFileDialog::~BrowseFileDialog()
{
    delete label;
    delete lineEdit;
    delete pushButtonBrowse;
    delete pushButtonOK;
    delete pushButtonCancel;
}

void BrowseFileDialog::initLayout()
{
    QGridLayout* mainLayout = new QGridLayout(this);
    QHBoxLayout* hBoxLayout = new QHBoxLayout();
    hBoxLayout->setSpacing(0);
    hBoxLayout->setMargin(0);
    label = new QLabel("Image File Path :");
    lineEdit = new QLineEdit(this);
    lineEdit->setReadOnly(true);
    pushButtonBrowse = new QPushButton("Browse...");
    hBoxLayout->addWidget(label);
    hBoxLayout->addWidget(lineEdit);
    hBoxLayout->addWidget(pushButtonBrowse);
    QHBoxLayout* actionWidgetsHBoxLayout = new QHBoxLayout();
    pushButtonCancel = new QPushButton("Cancel");
    pushButtonOK = new QPushButton("OK");
    actionWidgetsHBoxLayout->addStretch();
    actionWidgetsHBoxLayout->addWidget(pushButtonCancel);
    actionWidgetsHBoxLayout->addWidget(pushButtonOK);
    mainLayout->addLayout(hBoxLayout,0,0);
    mainLayout->addLayout(actionWidgetsHBoxLayout,1,0);
    setLayout(mainLayout);
}

void BrowseFileDialog::initConnections()
{
    connect(pushButtonBrowse, SIGNAL(clicked()), this, SLOT(sl_browseImage()));
    connect(pushButtonOK, SIGNAL(clicked()), this, SLOT(accept()));
    connect(pushButtonCancel, SIGNAL(clicked()), this, SLOT(reject()));
}

void BrowseFileDialog::sl_browseImage()
{
    QString inputImagePath=QFileDialog::getOpenFileName(this,tr("Select Image File"),QDir::currentPath(),
                                                        tr("All Files (*.*);;JPEG (*.jpeg *.jpg);;PNG (*.png)"));
    if(isValidImageFile(inputImagePath))
        lineEdit->setText(inputImagePath);
    else {
            QMessageBox::information(this, tr("Error!"),
                    tr("Please Provide a valid input image with JPG,JPEG or PNG extension!"));
    }
}

bool BrowseFileDialog::isValidImageFile(const QString& strImageFileName)
{
    QStringList acceptedImageFileTypeList;
    acceptedImageFileTypeList << "JPG"<< "JPEG" << "PNG";
    QStringList splittedStrList = strImageFileName.split(".");
    if( ((splittedStrList.size())-1) >= 0) {
        QString fileExtensionToCheck = splittedStrList[((splittedStrList.size())-1)];
        if( acceptedImageFileTypeList.contains(fileExtensionToCheck.toUpper()) )
            return true;
        else
            return false;
    }
    else
        return false;
}

BrowseFileDialog:

Application created by QT Creator and uses Qt4.7 .