Qt IOC Container 3.5


Getting Started

The code explained below can be found in test/test_plugin and test/test_app/application_context_test.

My First Plugin Object

ShapeInterface.h

We want to design to interface. So here's the interface. To let the Qt system know the interface, it is declared using Q_DECLARE_INTERFACE.

#ifndef SHAPE_INTERFACE_H_
#define SHAPE_INTERFACE_H_

class ShapeInterface
{
public:
  // Define virtual destructor so that objects of derived classes 
  // can be deleted using pointer of ShapeInterface.
  virtual ~ShapeInterface() {}

  virtual void draw () = 0;
};

// Declare the interface.
Q_DECLARE_INTERFACE(ShapeInterface, "org.qic.test.ShapeInterface/1.0")

#endif

RectanglePlugin.h

Now, a plugin to implement the interface. This class has to derive from QObject and all the interfaces it implements. Use Q_INTERFACES to tell Qt the interfaces it implements. To define properties that refer to other objects, the QObject * should be wrapped in QVariant.

#ifndef RECTANGLE_PLUGIN_H_
#define RECTANGLE_PLUGIN_H_

#include <QObject>
#include <QtDebug>
#include <QVariant>

#include "ShapeInterface.h"

//QObject must be the first base class.
class RectanglePlugin : public QObject, public ShapeInterface
{
  // For Qt Meta system 
  Q_OBJECT

  // Tell Qt that this class implements ShapeInterface.
  Q_INTERFACES( ShapeInterface)

  // Define some properties.
  // Value properties.
  Q_PROPERTY(QString name READ name WRITE setName)
  Q_PROPERTY(int size READ size WRITE setSize)

  // Property to reference another object.
  Q_PROPERTY(QVariant canvasObj READ canvasObj WRITE setCanvasObj)

public:
  RectanglePlugin ()
  {
    _name = "rectangle_plugin";
    _size = 0;
  }

  void draw ();

  QVariant canvasObj ()
  {
    // Wrap QObject * in QVariant.
    return QVariant::fromValue(_canvasObj);
  }

  void setCanvasObj (QVariant obj)
  {
    _canvasObj = obj.value<QObject *>();
  }

  int size () const
  {
    return _size;
  }

  void setSize (int size)
  {
    _size = size;
  }

  QString name () const
  {
    return _name;
  }

  void setName (QString & name)
  {
    _name = name;
  }

public slots:
  // Init method.
  void init ()
  {
    _size = 200;
  }

  void setCanvasSize (int size)
  {
    _size = size;
  }

  // Destroy method.
  void destroy ()
  {
    qDebug() << "In RectanglePlugin destroy method.";
  }

protected:
  QObject * _canvasObj;
  QString _name;
  int _size;

};

#endif

RectanglePlugin.cpp

Export the plugin using Q_EXPORT_PLUGIN2

#include <QtDebug>
#include <QString>
#include <QtPlugin>
#include <QtXml/QDomElement>

#include "RectanglePlugin.h"

void RectanglePlugin::draw ()
{
  qDebug()<< "Drawing RectanglePlugin. ";
}

// Tell Qt to export this plugin.
Q_EXPORT_PLUGIN2(rectangle_plugin, RectanglePlugin)

rectangle_plugin.pro

HEADERS += RectanglePlugin.h \
           ../ShapeInterface.h 
SOURCES += RectanglePlugin.cpp 
INCLUDEPATH += ../ \
               ./ \
               ../../../include 
CONFIG += debug \
          warn_on \
          qt \
          plugin 
TEMPLATE = lib 

Another Plugin Object

Canvas Object emits sizeChanged signal when its size property is set.

CanvasPlugin.h

#ifndef CANVAS_PLUGIN_H_
#define CANVAS_PLUGIN_H_

#include <QObject>
#include <QList>
#include <QMetaType>
#include <QVariant>
#include <QtDebug>

#include "ShapeInterface.h"

class CanvasPlugin : public QObject, public ShapeInterface
{
  Q_OBJECT
  Q_INTERFACES(ShapeInterface)
  Q_PROPERTY(int size READ size WRITE setSize)
  // QObject * as a property
  Q_PROPERTY(QVariant rectangleObj READ rectangleObj WRITE setRectangleObj)

public:
  CanvasPlugin ()
  {
    _rectangleObj = NULL;
    _size = 0;
  }

  virtual ~CanvasPlugin () {}

  virtual void draw ();

  QVariant rectangleObj ()
  {
    return QVariant::fromValue(_rectangleObj);
  }

  void setRectangleObj (QVariant obj)
  {
    _rectangleObj = obj.value<QObject *>();
  }

  int size () const
  {
    return _size;
  }

  void setSize (int size)
  {
    if (size != _size)
    {
      _size = size;
      emit sizeChanged(_size);
    }

  }

public slots:
  // Init method.
  void init ()
  {
    _size = 200;
  }

signals:
  void sizeChanged(int newValue);

protected:
  QObject * _rectangleObj;
  int _size;
};

#endif

CanvasPlugin.cpp

#include <QtDebug>
#include <QString>
#include <QtPlugin>

#include "CanvasPlugin.h"

void
CanvasPlugin::draw ()
{
  qDebug() << "Drawing CanvasPlugin.";
  if (_rectangleObj)
  {
    ShapeInterface * shape = qobject_cast<ShapeInterface *>(_rectangleObj);
    shape->draw();
  }

}

Q_EXPORT_PLUGIN2(canvas_plugin, CanvasPlugin)

canvas_plugin.pro

HEADERS += ../ShapeInterface.h \
           CanvasPlugin.h 
SOURCES += CanvasPlugin.cpp 
INCLUDEPATH += ../../../include \
               ./ \
               ../ 
CONFIG += debug \
          warn_on \
          qt \
          plugin 
TEMPLATE = lib 

Configuration File

Now the configuration file to wire up the objects.

<objects>

<object id="rectangle" 
        plugin="${QIC_DIR}/test/test_plugin/rectangle_plugin/librectangle_plugin.so"
        init-method="init" destroy-method="destroy" >
        <property name="name">
                <value><null/></value>
        </property>
        <property name="size">
                <value>100</value>
        </property>
</object>

<object id="canvas" 
        plugin="${QIC_DIR}/test/test_plugin/canvas_plugin/libcanvas_plugin.so" >
        <property name="rectangleObj" ref="rectangle">
        </property>
</object>

<!-- Wire the signal and slot. -->
<wire type="auto">
        <sender id="canvas" signal="sizeChanged(int)">
        </sender>
        <receiver id="rectangle" method="setCanvasSize(int)">
        </receiver>
</wire>

</objects>

Test the application

QString base = qic::Util::getEnvVariable("QIC_DIR");
base.append("/test/test_app/application_context_test/");

qic::XmlApplicationContext ctx( 
                QStringList() << (base + "application_context_10.xml") );

QObject * obj = ctx.getObject("canvas");

// Draw the Canvas
ShapeInterface * shape = qobject_cast<ShapeInterface *>(obj);
shape->draw();

// Test the wiring of signal and slot
obj->setProperty("size", 111);

obj = ctx.getObject( "rectangle");
int size = obj->property("size").value<int>();
// size should be 111 now.