Monday, October 25, 2010

Log Time, Date, FileName, FunctionName, LineNumber for QT Applications in C++

Logging provides developers with detailed information about program flow. Logging also makes tracing of exceptions occured easier at run-time. By including date, time, filename, functionname, linenumber into a text file; it becomes a helpful guide for program flow trace. C++ comes with macros that are usable for logging purposes.
"__FILE__" macro gives information about the curent fileName and returns a string. "__FUNCTION__" macro gives information about the name of the current function and returns a string. "__LINE__" macro gives information about the current line number and returns an integer value. These are ANSI-Compliant Predefined Macros.
Logger.h file contains declaration for Log class.
#include <fstream>
#include <QString>
using namespace std;

class Log {
public:
 Log();
 ~Log();
 void trace(QString fileName, QString functionName, int lineNumber);
private:
 ofstream myFile;
 char stime[9];
 char sdate[9];
};


Logger.cpp file contains implementation for Log class. trace() method takes fileName, functionName and lineNumber as parameters.
#include <fstream>
#include "Logger.h"
#include <time.h>
using namespace std;

Log::Log() {
}

void Log::trace(QString fileName, QString functionName, int lineNumber) {
 _strtime(stime);
 _strdate(sdate);
 myFile.open("C:\\example.txt", fstream::in | fstream::out | fstream::app);
 myFile<<"Date:"<<sdate<<";"<<" Time:"<<stime<<";"<<" FileName:"<<qPrintable(fileName)<<";"<<" FunctionName:"<<qPrintable(functionName)<<";"<<" LineNo:"<<lineNumber<<endl;
 myFile.close(); 
}

Log::~Log(){
 myFile.close();
}


main.cpp file uses Log class trace method for logging purposes.
#include "logger.h"
int main(int argc, char *argv[])
{
   Log* logger = new Log();
   logger->trace(__FILE__, __FUNCTION__, __LINE__);
   return 0;
}


trace method produces the output to the example.txt file that is located under the c:\ root directory. Sample output is generated as follows:
Date:10/25/10; Time:21:07:25; FileName:.\main.cpp; FunctionName:main; LineNo:5

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