{"id":73,"date":"2020-01-22T13:00:20","date_gmt":"2020-01-22T13:00:20","guid":{"rendered":"https:\/\/www.vcreatelogic.com\/?p=73"},"modified":"2020-01-23T05:05:16","modified_gmt":"2020-01-23T05:05:16","slug":"qobjectfactory","status":"publish","type":"post","link":"https:\/\/www.vcreatelogic.com\/index.php\/2020\/01\/22\/qobjectfactory\/","title":{"rendered":"QObjectFactory"},"content":{"rendered":"\n<p><a rel=\"noreferrer noopener\" aria-label=\"Factory Design Pattern (opens in a new tab)\" href=\"https:\/\/en.wikipedia.org\/wiki\/Factory_method_pattern\" target=\"_blank\">Factory Design Pattern<\/a> is a well known pattern. Its a way to organise code so that class-instances can be created at run time against a developer defined key. Factories specialise in create objects of a specific type. For example (yes, this example is inspired from the example on the Wikipedia page about <a href=\"https:\/\/en.wikipedia.org\/wiki\/Factory_method_pattern\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Factory Design Pattern (opens in a new tab)\">Factory Design Pattern<\/a>s)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#define interface class\n#define implements : public\n\ninterface IPerson\n{\npublic:\n    virtual std::string getType() = 0;\n};\n\nclass VillagePerson implements IPerson\n{\npublic:\n    virtual std::string getType() { return \"VillagePerson\"; }\n};\n\nclass TownPerson implements IPerson\n{\npublic:\n    virtual std::string getType() { return \"TownPerson\"; }\n};\n\nclass CityPerson implements IPerson\n{\npublic:\n    virtual std::string getType() { return \"CityPerson\"; }\n};\n\nclass PersonFactory\n{\npublic:\n    IPerson *createPerson(const std::string &amp;type) {\n        if(type == \"VillagePerson\")\n            return new VillagePerson;\n        if(type == \"TownPerson\")\n            return new TownPerson;\n        if(type == \"CityPerson\")\n            return new CityPerson;\n        return nullptr;\n    }\n};<\/code><\/pre>\n\n\n\n<p>So, we can now create instances of IPerson using the PersonFactory class. For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PersonFactory factory;\nIPerson *person = factory.createPerson(\"CityPerson\");<\/code><\/pre>\n\n\n\n<p>Now person will point to an instance of CityPerson class. Thats the whole point of a factory, to create object instances based on a key. In this case the key was type name as string.<\/p>\n\n\n\n<p>Qt uses Factory Design Pattern in several places. For example the <a rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\" href=\"https:\/\/doc.qt.io\/qt-5\/qitemeditorfactory.html\" target=\"_blank\">QItemEditorFactory<\/a> class helps create editor widgets for items in a QAbstractItemView. Over there the type is integer. There is also a <a rel=\"noreferrer noopener\" aria-label=\"QStyleFactory (opens in a new tab)\" href=\"https:\/\/doc.qt.io\/qt-5\/qstylefactory.html\" target=\"_blank\">QStyleFactory<\/a> that creates instances of QStyle based on style-name as key. <\/p>\n\n\n\n<p>Almost every software project that I have been a part of makes use of the factory design pattern. Almost all of the factory classes I have written create QObject subclasses based on a QString or QByteArray key. Typically the key is name of the QObject subclass, but its not always the case. After one writes enough number of factories, it becomes boring to write the same thing over and over again. So I came up with a simple solution. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">QObjectFactory class<\/h3>\n\n\n\n<p>Lets take the same example as before. Suppose we wanted to create a Person factory class. Lets also suppose that we can make peace with the fact that objects created by our factory will be QObject subclasses. So the person interface and subclasses would look like this<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class AbstractPerson : public QObject\n{\n    Q_OBJECT\n\npublic:\n    AbstractPerson(QObject *parent=nullptr)\n        : QObject(parent) { }\n    ~AbstractPerson() { }\n\n    virtual QByteArray getType() const = 0;\n};\n\nclass VillagePerson : public AbstractPerson\n{\n    Q_OBJECT\n\npublic:\n    Q_INVOKABLE VillagePerson(QObject *parent=nullptr)\n        : AbstractPerson(parent) { }\n    ~VillagePerson() { }\n\n    virtual QByteArray getType() const {\n        return \"VillagePerson\";\n    }\n};\n\nclass TownPerson : public AbstractPerson\n{\n    Q_OBJECT\n\npublic:\n    Q_INVOKABLE TownPerson(QObject *parent=nullptr)\n        : AbstractPerson(parent) { }\n    ~TownPerson() { }\n\n    virtual QByteArray getType() const {\n        return \"VillagePerson\";\n    }\n};<\/code><\/pre>\n\n\n\n<p>Notice the following<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>AbstractPerson is subclassed from QObject<\/li><li>AbstractPerson and all its subclasses have Q_OBJECT macro declared in them<\/li><li>AbstractPerson and all its subclasses have a constructor that accepts a parent pointer.<\/li><li>Subclasses of AbstractPerson have their constructor marked as Q_INVOKABLE<\/li><\/ul>\n\n\n\n<p>Now, lets register subclasses of AbstractPerson in a factory.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>QObjectFactory factory;\nfactory.addClass&lt;VillagePerson>();\nfactory.addClass&lt;TownPerson>();\nfactory.addClass&lt;CityPerson>();<\/code><\/pre>\n\n\n\n<p>That&#8217;s it. Creation of instances from the factory would be as simple as<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>AbstractPerson *person = factory.create&lt;AbstractPerson>(\"CityPerson\");<\/code><\/pre>\n\n\n\n<p>Seems magical right? Let&#8217;s look at how the QObjectFactory class is written.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class QObjectFactory\n{\npublic:\n    QObjectFactory() { }\n    ~QObjectFactory() { }\n\n    void add(const QMetaObject *mo) { m_metaObjects += mo; }\n    void remove(const QMetaObject *mo) { m_metaObjects -= mo; }\n\n    template &lt;class T>\n    void addClass() { this->add( &amp;T::staticMetaObject ); }\n\n    template &lt;class T>\n    void removeClass() { this->remove( &amp;T::staticMetaObject ); }\n\n    const QMetaObject *find(const QByteArray &amp;className) const {\n        Q_FOREACH(const QMetaObject *mo, m_metaObjects) {\n            if( !qstrcmp(className.data(), mo->className()) )\n                return mo;\n        }\n        return nullptr;\n    }\n\n    QObject *create(const QByteArray &amp;className, QObject *parent=nullptr) const {\n        const QMetaObject *mo = this->find(className);\n        if(mo == nullptr)\n            return nullptr;\n        QObject *obj = mo->newInstance(Q_ARG(QObject*,parent));\n        return obj;\n    }\n\n    template &lt;class T>\n    T *create(const QByteArray &amp;className, QObject *parent=nullptr) const {\n        QObject *obj = this->create(className, parent);\n        return qobject_cast&lt;T*>(obj);\n    }\n\nprivate:\n    QSet&lt;const QMetaObject*> m_metaObjects;\n};<\/code><\/pre>\n\n\n\n<p>Qt&#8217;s <a rel=\"noreferrer noopener\" aria-label=\"QMetaObject (opens in a new tab)\" href=\"https:\/\/doc.qt.io\/qt-5\/qmetaobject.html\" target=\"_blank\">QMetaObject<\/a> class provides a <a rel=\"noreferrer noopener\" aria-label=\"newInstance() method (opens in a new tab)\" href=\"https:\/\/doc.qt.io\/qt-5\/qmetaobject.html#newInstance\" target=\"_blank\">newInstance() method<\/a> that helps us call the constructor of  its QObject class using a transparent API. By using some really simple template constructs, we make the QObjectFactory class look magical.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can we use QObjectFactory for creating widgets?<\/h3>\n\n\n\n<p>QWidget and subclasses accept a QWidget* as parent pointer, instead of QObject*. So, the QObjectFactory class in its current incarnation cannot be used as a QWidget factory. We will need to write a QWidgetFactory class, that does pretty much the same thing, just that the parent pointer will be of type QWidget*. Or, we can do something smarter.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>template &lt;class T>\nclass QtFactory\n{\npublic:\n    QtFactory() { }\n    ~QtFactory() { }\n\n    void add(const QMetaObject *mo) { m_metaObjects += mo; }\n    void remove(const QMetaObject *mo) { m_metaObjects -= mo; }\n\n    template &lt;class Class>\n    void addClass() { this->add( &amp;Class::staticMetaObject ); }\n\n    template &lt;class Class>\n    void removeClass() { this->remove( &amp;Class::staticMetaObject ); }\n\n    const QMetaObject *find(const QByteArray &amp;className) const {\n        Q_FOREACH(const QMetaObject *mo, m_metaObjects) {\n            if( !qstrcmp(className.data(), mo->className()) )\n                return mo;\n        }\n        return nullptr;\n    }\n\n    T *create(const QByteArray &amp;className, T *parent=nullptr) const {\n        const QMetaObject *mo = this->find(className);\n        if(mo == nullptr)\n            return nullptr;\n\n        const char *t = this->type();\n        QObject *obj = qobject_cast&lt;T*>(mo->newInstance( QArgument&lt;T*>(t,parent) ));\n        return qobject_cast&lt;T*>(obj);\n    }\n\n    template &lt;class Class>\n    Class *create(const QByteArray &amp;className, T *parent=nullptr) const {\n        T *obj = this->create(className, parent);\n        return qobject_cast&lt;Class*>(obj);\n    }\n\nprivate:\n    const char *type() const {\n        static const char *qobjectstar = \"QObject*\";\n        static const char *qwidgetstar = \"QWidget*\";\n        if( typeid(T) == typeid(QWidget) )\n            return qwidgetstar;\n        return qobjectstar;\n    }\n\nprivate:\n    QSet&lt;const QMetaObject*> m_metaObjects;\n};\n\ntypedef QtFactory&lt;QObject> QObjectFactory;\ntypedef QtFactory&lt;QWidget> QWidgetFactory;<\/code><\/pre>\n\n\n\n<p>Notice how QtFactory is now a generic template class and we create QObjectFactory and QWidgetFactory from it. Now we can use QWidgetFactory as follows<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class LineEdit : public QLineEdit\n{\n    Q_OBJECT\n\npublic:\n    Q_INVOKABLE LineEdit(QWidget *parent=nullptr)\n        : QLineEdit(parent) { }\n    ~LineEdit() { }\n};\n\nclass PushButton : public QPushButton\n{\n    Q_OBJECT\n\npublic:\n    Q_INVOKABLE PushButton(QWidget *parent=nullptr)\n        : QPushButton(parent) {\n        this->setText(\"Button\");\n    }\n    ~PushButton() { }\n};\n\nint main(int argc, char **argv)\n{\n    QApplication a(argc, argv);\n\n    QWidgetFactory factory;\n    factory.addClass&lt;LineEdit>();\n    factory.addClass&lt;PushButton>();\n\n    QWidget window;\n    QVBoxLayout *layout = new QVBoxLayout(&amp;window);\n\n    layout->addWidget(factory.create(\"LineEdit\", &amp;window));\n    layout->addWidget(factory.create(\"PushButton\", &amp;window));\n\n    window.show();\n\n    return a.exec();\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">How about key as something other than class name?<\/h3>\n\n\n\n<p>So far we are using class-name as the lookup key in the factory class. What if we wanted to use as key something other class-names? For example, we may want a widget-factory that helps us create widgets based on the type of data we want to edit using it. We can make use of Q_CLASSINFO() to add additional data about the widget class into its QMetaObject as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class LineEdit : public QLineEdit\n{\n    Q_OBJECT\n    Q_CLASSINFO(\"DataTypes\", \"QString;QUrl\")\n\npublic:\n    Q_INVOKABLE LineEdit(QWidget *parent=nullptr)\n        : QLineEdit(parent) { }\n    ~LineEdit() { }\n};\n\nclass CheckBox : public QCheckBox\n{\n    Q_OBJECT\n    Q_CLASSINFO(\"DataTypes\", \"bool\")\n\npublic:\n    Q_INVOKABLE CheckBox(QWidget *parent=nullptr)\n        : QCheckBox(parent) {\n        this->setText(\"Yes\/No\");\n    }\n    ~CheckBox() { }\n};<\/code><\/pre>\n\n\n\n<p>Now, we update the QtFactory class to lookup based on the semi-colon separated list in value to DataTypes Q_CLASSINFO.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>template &lt;class T>\nclass QtFactory\n{\npublic:\n    QtFactory(const QByteArray &amp;key=QByteArray()) : m_classInfoKey(key) { }\n    ~QtFactory() { }\n\n    QByteArray classInfoKey() const { return m_classInfoKey; }\n\n    void add(const QMetaObject *mo) {\n        QList&lt;QByteArray> keys;\n        const int ciIndex = mo->indexOfClassInfo(m_classInfoKey.constData());\n        if(ciIndex >= 0) {\n            const QMetaClassInfo ci = mo->classInfo(ciIndex);\n            keys = QByteArray(ci.value()).split(';');\n        }\n        keys.append( QByteArray(mo->className()) );\n        m_metaObjects.insert(mo, keys);\n        Q_FOREACH(QByteArray key, keys)\n            m_keyMap[key].append(mo);\n    }\n\n    void remove(const QMetaObject *mo) {\n        const QList&lt;QByteArray> keys = m_metaObjects.take(mo);\n        Q_FOREACH(QByteArray key, keys) {\n            QList&lt;const QMetaObject *> mos = m_keyMap.take(key);\n            mos.removeOne(mo);\n            if(mos.isEmpty())\n                continue;\n            m_keyMap[key] = mos;\n        }\n    }\n\n    \/\/ ...\n\n    QList&lt;QByteArray> keys() const { return m_keyMap.keys(); }\n\n    const QMetaObject *find(const QByteArray &amp;val) const {\n        const QList&lt;const QMetaObject *> mos = m_keyMap.value(val);\n        return mos.isEmpty() ? nullptr : mos.last();\n    }\n\n    \/\/ ...\n\nprivate:\n    QMap&lt;const QMetaObject*, QList&lt;QByteArray> > m_metaObjects;\n    QMap&lt;QByteArray, QList&lt;const QMetaObject *> > m_keyMap;\n    QByteArray m_classInfoKey;\n};<\/code><\/pre>\n\n\n\n<p>Notice how the factory class now uses both class-names and Q_CLASSINFO data to lookup which class to create an instance of. <\/p>\n\n\n\n<p>Now we can use the QWidgetFactory class as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>int main(int argc, char **argv)\n{\n    QApplication a(argc, argv);\n\n    QWidgetFactory factory(\"DataTypes\");\n    factory.addClass&lt;LineEdit>();\n    factory.addClass&lt;CheckBox>();\n\n    QWidget window;\n    QVBoxLayout *layout = new QVBoxLayout(&amp;window);\n\n    layout->addWidget(factory.create(\"QString\", &amp;window));\n    layout->addWidget(factory.create(\"QUrl\", &amp;window));\n    layout->addWidget(factory.create(\"bool\", &amp;window));\n\n    window.show();\n\n    return a.exec();\n}<\/code><\/pre>\n\n\n\n<p>The entire widget factory is just a header file. You can expand this block to view\/copy the entire code.<\/p>\n\n\n\n<details><summary>QtFactory Source Code<\/summary>\n<pre>\/****************************************************************************\n**\n** Copyright (C) Prashanth Udupa, Bengaluru\n** Email: prashanth.udupa@gmail.com\n**\n** This code is distributed under LGPL v3. Complete text of the license\n** can be found here: https:\/\/www.gnu.org\/licenses\/lgpl-3.0.en.html\n**\n** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE\n** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.\n**\n****************************************************************************\/\n\n#ifndef QOBJECTFACTORY_H\n#define QOBJECTFACTORY_H\n\n#include &lt;QSet&gt;\n#include &lt;QMap&gt;\n#include &lt;QWidget&gt;\n#include &lt;QObject&gt;\n#include &lt;QMetaObject&gt;\n#include &lt;QMetaClassInfo&gt;\n\ntemplate &lt;class T&gt;\nclass QtFactory\n{\npublic:\n    QtFactory(const QByteArray &key=QByteArray()) : m_classInfoKey(key) { }\n    ~QtFactory() { }\n\n    QByteArray classInfoKey() const { return m_classInfoKey; }\n\n    void add(const QMetaObject *mo) {\n        QList&lt;QByteArray&gt; keys;\n        const int ciIndex = mo-&gt;indexOfClassInfo(m_classInfoKey.constData());\n        if(ciIndex &gt;= 0) {\n            const QMetaClassInfo ci = mo-&gt;classInfo(ciIndex);\n            keys = QByteArray(ci.value()).split(';');\n        }\n        keys.append( QByteArray(mo-&gt;className()) );\n        m_metaObjects.insert(mo, keys);\n        Q_FOREACH(QByteArray key, keys)\n            m_keyMap[key].append(mo);\n    }\n    void remove(const QMetaObject *mo) {\n        const QList&lt;QByteArray&gt; keys = m_metaObjects.take(mo);\n        Q_FOREACH(QByteArray key, keys) {\n            QList&lt;const QMetaObject *&gt; mos = m_keyMap.take(key);\n            mos.removeOne(mo);\n            if(mos.isEmpty())\n                continue;\n            m_keyMap[key] = mos;\n        }\n    }\n\n    template &lt;class Class&gt;\n    void addClass() { this-&gt;add( &Class::staticMetaObject ); }\n\n    template &lt;class Class&gt;\n    void removeClass() { this-&gt;remove( &Class::staticMetaObject ); }\n\n    QList&lt;QByteArray&gt; keys() const { return m_keyMap.keys(); }\n\n    const QMetaObject *find(const QByteArray &val) const {\n        const QList&lt;const QMetaObject *&gt; mos = m_keyMap.value(val);\n        return mos.isEmpty() ? nullptr : mos.last();\n    }\n\n    T *create(const QByteArray &className, T *parent=nullptr) const {\n        const QMetaObject *mo = this-&gt;find(className);\n        if(mo == nullptr)\n            return nullptr;\n        const char *t = this-&gt;type();\n        QObject *obj = qobject_cast&lt;T*&gt;(mo-&gt;newInstance( QArgument&lt;T*&gt;(t,parent) ));\n        return qobject_cast&lt;T*&gt;(obj);\n    }\n\n    template &lt;class Class&gt;\n    Class *create(const QByteArray &className, T *parent=nullptr) const {\n        T *obj = this-&gt;create(className, parent);\n        return qobject_cast&lt;Class*&gt;(obj);\n    }\n\nprivate:\n    const char *type() const {\n        static const char *qobjectstar = \"QObject*\";\n        static const char *qwidgetstar = \"QWidget*\";\n        if( typeid(T) == typeid(QWidget) )\n            return qwidgetstar;\n        return qobjectstar;\n    }\n\nprivate:\n    QMap&lt;const QMetaObject*, QList&lt;QByteArray&gt; &gt; m_metaObjects;\n    QMap&lt;QByteArray, QList&lt;const QMetaObject *&gt; &gt; m_keyMap;\n    QByteArray m_classInfoKey;\n};\n\ntypedef QtFactory&lt;QObject&gt; QObjectFactory;\ntypedef QtFactory&lt;QWidget&gt; QWidgetFactory;\n\n#endif \/\/ QOBJECTFACTORY_H\n<\/pre>\n<\/details>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Factory Design Pattern is a well known pattern. Its a way to organise code so that class-instances can be created at run time against a developer defined key. Factories specialise in create objects of a specific type. For example (yes, this example is inspired from the example on the Wikipedia page about Factory Design Patterns) &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.vcreatelogic.com\/index.php\/2020\/01\/22\/qobjectfactory\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;QObjectFactory&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-73","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/posts\/73","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/comments?post=73"}],"version-history":[{"count":15,"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/posts\/73\/revisions"}],"predecessor-version":[{"id":161,"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/posts\/73\/revisions\/161"}],"wp:attachment":[{"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/media?parent=73"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/categories?post=73"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.vcreatelogic.com\/index.php\/wp-json\/wp\/v2\/tags?post=73"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}