Простой пример создания ActiveX-control на Qt

от автора

Введение

Мне была поставлена задача разработать некий ActiveX-control. Так как основным языком программирования для разработки у нас используется C++, то C# не рассматривался. Я решил выбрать Qt, так как он мне интересен.

Создание ActiveX объектов на Qt достаточно простой процесс, в примерах к QtCreator есть несколько вариантов, показывающих как можно использовать ActiveQt (например этот).

При написании компонента пришлось много времени потратить на поиск ответов на казалось бы простые вопросы, по крупицам их собирать. В результате я получил, что требовалось и решил написать простой пример, чтобы ускорить процесс старта разработки ActiveX-control другим.

Сразу обращу внимание, что не описываю всю технологию ActiveQt, подробную информацию можно получить в документации Qt Assistant и в интернете (например здесь), это пример и пара интересных на мой взгляд моментов.

Начало

Итак, для начала устанавливаем QtSDK (я выбрал коммерческую версию в связке с MS VisualStudio 2010).

Создаем пустой проект. В качестве примера создадим ActiveX-control с цифровыми часами (возьмем пример отсюда).

Добавляем в наш проект класс цифровых часов.
Добавляем файл main.cpp, в нем создадим класс, унаследованный от QAxFactory. Этот класс реализовывает фабрику, предоставляющую информацию об элементах управления и создает их по запросу.

#include <QAxFactory> #include "clock.h" // заголовочный файл класса цифровых часов  class ActiveQtFactory : public QAxFactory { public:     ActiveQtFactory( const QUuid &lib, const QUuid &app )     : QAxFactory( lib, app )      {}     // список импортируемых классов     QStringList featureList() const     {         QStringList list;        // если классов будет несколько, то нужно будет добавить в список имя каждого        //  в данном пример только один "Clock"         list << "Clock";         return list;     }     // создание объекта экспортируемого класса     QObject *createObject(const QString &key)     {         if ( key == "Clock" )             return new Clock();        // аналогично для каждого класса         return 0;     }     // получение мета-информации о классе     const QMetaObject *metaObject( const QString &key ) const     {         if ( key == "Clock" )             return &Clock::staticMetaObject;        // аналогично для каждого класса         return 0;     } };  // экспорт фабрики QAXFACTORY_EXPORT( ActiveQtFactory, "{c1de5776-a143-4884-89fc-81a06d04e87d}", "{11403913-dc94-484a-af5a-521f0e93d2ee}" ) 

Если захотим в библиотеку добавить другие классы, то нужно подключить их заголовочные файлы и добавить описание в класс ActiveQtFactory

Теперь доработаем класс Clock для экспортирования его метаданных:
В заголовок добавим макрос для динамической библиотеки

// ........... #include <qglobal.h>  #if defined(Clock_LIBRARY) #  define Clock_LIBRARY Q_DECL_EXPORT #else #  define Clock_LIBRARY Q_DECL_IMPORT #endif  class Clock_LIBRARY Clock : public QLCDNumber { // ........... 

Добавим информацию о классе

        // ..............     Q_OBJECT     Q_CLASSINFO("ClassID", "{1edd41d0-e01f-445d-9b4e-78c99ab93acf}")     Q_CLASSINFO("InterfaceID", "{8adccb5c-567e-42f6-8b81-f6634409fb1a}")     Q_CLASSINFO("EventsID", "{f0a4474f-8c0c-4cdf-985d-8379b26bdd19}")     // ..............  

Для каждого класса необходимо указывать свои ClassID, InterfaceID, EventsID.

Заключительный момент, скорректируем файл проекта

TEMPLATE = lib CONFIG	+= qt qaxserver dll contains(CONFIG, static):DEFINES += QT_NODLL  SOURCES	 = main.cpp \    clock.cpp  HEADERS += \        clock.h  DEF_FILE = qaxserver.def DEFINES += clock_LIBRARY VERSION = 0.0.0.1  # Подключаем заголовочные файлы библиотеки INCLUDEPATH += clock TARGET	 = clock 

Компилируем, получаем библиотеку.
Это все описано в документации, теперь несколько дополнений, ради которых собственно я и решил написать статью.

Добавить свойство

Необходимо добавить экспортное свойство класса. Для примера возьмем некое name;
Доработаем класс Clock

   // .................     Q_OBJECT     Q_CLASSINFO("ClassID", "{1edd41d0-e01f-445d-9b4e-78c99ab93acf}")     Q_CLASSINFO("InterfaceID", "{8adccb5c-567e-42f6-8b81-f6634409fb1a}")     Q_CLASSINFO("EventsID", "{f0a4474f-8c0c-4cdf-985d-8379b26bdd19}")     // добавим свойство name     Q_PROPERTY(QString name READ getName WRITE setName)  public:    // функция получения свойства      QString getName()const     {         if(name.isEmpty())             return "Clock";         else             return name;     }    // функция установки свойства     void setName(const QString &inName){name = inName;} private:     QString name; // ....... 
Добавить метод

Методы добавляются через публичные слоты в классе Clock:

// ....... public slots:     void function(int a);     QString functionb(const QString &b); // ....... 
Добавить событие

Событие, реакцию на которое вы хотите реализовать в алгоритме использующем AXControl, добавляется через сигналы, ниже пример, правда из другого класса:

 // в классе создаем сигнал signals:     void mouseDbClick(int x, int y);  // переопределяем событие protected:      void mouseDoubleClickEvent(QMouseEvent *event)      {         QPoint pos = event->pos();         emit mouseDbClick(pos.rx(), pos.ry());     }  

Заключение

Библиотека Qt отличная вещь, может очень многое, нужно учится ее готовить.

Отдельная благодарность автору статьи о создании динамических библиотек Qt.
Полезные ресурсы, которые помогли в решении задачи doc.crossplatform.ru/qt и qt-project.org

ссылка на оригинал статьи http://habrahabr.ru/post/170607/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *