- Qt 6.4
- Active Qt
- Hierarchy Example (ActiveQt)
- Qt 6.4.3 Reference Documentation

# Hierarchy Example (ActiveQt)

The Hierarchy example is shows how to write an in-process ActiveX control. The control is a QWidget subclass with child widgets that are accessible as sub-types.

     class QParentWidget : public QWidget
     {
         Q_OBJECT
         Q_CLASSINFO("ClassID", "{d574a747-8016-46db-a07c-b2b4854ee75c}");
         Q_CLASSINFO("InterfaceID", "{4a30719d-d9c2-4659-9d16-67378209f822}");
         Q_CLASSINFO("EventsID", "{4a30719d-d9c2-4659-9d16-67378209f823}");
     public:
         explicit QParentWidget(QWidget *parent = nullptr);

         QSize sizeHint() const override;

     public slots:
         void createSubWidget(const QString &name);

         QSubWidget *subWidget(const QString &name);

     private:
         QVBoxLayout *m_vbox;
     };

The `QParentWidget` class provides slots to create a widget with a name, and to return a pointer to a named widget. The class declaration uses `Q_CLASSINFO()` to provide the COM identifiers for this class.

     QParentWidget::QParentWidget(QWidget *parent)
     : QWidget(parent),
       m_vbox(new QVBoxLayout(this))
     {
     }

The constructor of `QParentWidget` creates a vertical box layout. New child widgets are automatically added to the layout.

     void QParentWidget::createSubWidget(const QString &name)
     {
         QSubWidget *sw = new QSubWidget(this, name);
         m_vbox->addWidget(sw);
         sw->setLabel(name);
         sw->show();
     }

The `createSubWidget` slot creates a new `QSubWidget` with the name provided in the parameter, and sets the label to that name. The widget is also shown explicitly.

     QSubWidget *QParentWidget::subWidget(const QString &name)
     {
         return findChild<QSubWidget *>(name);
     }

The `subWidget` slot uses the `QObject::findChild()` function and returns the first child of type `QSubWidget` that has the requested name.

     class QSubWidget : public QWidget
     {
         Q_OBJECT
         Q_PROPERTY(QString label READ label WRITE setLabel)

         Q_CLASSINFO("ClassID", "{850652f4-8f71-4f69-b745-bce241ccdc30}");
         Q_CLASSINFO("InterfaceID", "{2d76cc2f-3488-417a-83d6-debff88b3c3f}");
         Q_CLASSINFO("ToSuperClass", "QSubWidget");

     public:
         QSubWidget(QWidget *parent = nullptr, const QString &name = QString());

         void setLabel(const QString &text);
         QString label() const;

         QSize sizeHint() const override;

     protected:
         void paintEvent(QPaintEvent *e) override;

     private:
         QString m_label;
     };

The `QSubWidget` class has a single string-property `label`, and implements the paintEvent to draw the label. The class uses again `Q_CLASSINFO` to provide the COM identifiers, and also sets the ToSuperClass attribute to QSubWidget, to ensure that only no slots of any superclasses (i.e. QWidget) are exposed.

     QSubWidget::QSubWidget(QWidget *parent, const QString &name)
     : QWidget(parent)
     {
         setObjectName(name);
     }

     void QSubWidget::setLabel(const QString &text)
     {
         m_label = text;
         setObjectName(text);
         update();
     }

     QString QSubWidget::label() const
     {
         return m_label;
     }

     QSize QSubWidget::sizeHint() const
     {
         QFontMetrics fm(font());
         return QSize(fm.horizontalAdvance(m_label), fm.height());
     }

     void QSubWidget::paintEvent(QPaintEvent *)
     {
         QPainter painter(this);
         painter.setPen(palette().text().color());
         painter.drawText(rect(), Qt::AlignCenter, m_label);
     }

The implementation of the `QSubWidget` class is self-explanatory.

     #include "objects.h"
     #include <QAxFactory>

     QAXFACTORY_BEGIN("{9e626211-be62-4d18-9483-9419358fbb03}", "{75c276de-1df5-451f-a004-e4fa1a587df1}")
         QAXCLASS(QParentWidget)
         QAXTYPE(QSubWidget)
     QAXFACTORY_END()

The classes are then exported using a QAxFactory. `QParentWidget` is exported as a full class (which can be created ), while `QSubWidget` is only exported as a type, which can only be created indirectly through APIs of `QParentWidget`.

To build the example you must first build the QAxServer library. Then run qmake and your make tool in `activeqt/hierarchy`.

The demonstration requires your WebBrowser to support ActiveX controls, and scripting to be enabled.

     <script language="javascript">
     function createSubWidget( form )
     {
         ParentWidget.createSubWidget( form.nameEdit.value );
     }

     function renameSubWidget( form )
     {
         var SubWidget = ParentWidget.subWidget( form.nameEdit.value );
         if ( !SubWidget ) {
             alert( "No such widget " + form.nameEdit.value + "!" );
             return;
         }
         SubWidget.label = form.labelEdit.value;
         form.nameEdit.value = SubWidget.label;
     }

     function setFont( form )
     {
         ParentWidget.font = form.fontEdit.value;
     }
     </script>

     <p>
     This widget can have many children!
     </p>
     <object ID="ParentWidget" CLASSID="CLSID:d574a747-8016-46db-a07c-b2b4854ee75c"
     CODEBASE="http://www.qt-project.org/demos/hierarchy.cab">
     [Object not available! Did you forget to build and register the server?]
     </object><br />
     <form>
     <input type="edit" ID="nameEdit" value="&lt;enter object name&gt;" />
     <input type="button" value="Create" onClick="createSubWidget(this.form)" />
     <input type="edit" ID="labelEdit" />
     <input type="button" value="Rename" onClick="renameSubWidget(this.form)" />
     <br />
     <input type="edit" ID="fontEdit" value="MS Sans Serif" />
     <input type="button" value = "Set Font" onClick="setFont(this.form)" />
     </form>

Example project @ code.qt.io