Плагины в Qt - динамически подключаемые библиотеки. Мы уже немного затрагивали преимущества от использования плагинов, когда говорили о создании гибкого кода.
А сейчас займемся практикой и напишем свой собственный Qt-плагин.
Опишем интерфейс плагина в файле myplugininterface.h
:
#ifndef MYPLUGININTERFACE_H
#define MYPLUGININTERFACE_H
#include <QString>
#include <QVariant>
#include <QtPlugin>
class MyPluginInterface {
public:
virtual ~MyPluginInterface() { }
virtual QString getString() const = 0;
virtual QVariant getVar() const = 0;
};
Q_DECLARE_INTERFACE( MyPluginInterface, "ru.itnotesblog.MyApp.MyPluginInterface/1.0" )
#endif // MYPLUGININTERFACE_H
MyPluginInterface
предоставляет две операции, возвращающих значения. Особый интерес представляет вторая (getVar()
), которая работает с обобщенным типом QVariant. С его помощью вы можете создавать сверх-универсальные интерфейсы.
Чтобы интерфейс можно было использовать для создания плагинов, необходимо применение макроса Q_DECLARE_INTERFACE
. Первым параметром он принимает класс интерфейса, а вторым - идентификационную строку.
Идентификационная строка состоит из нескольких частей (по структуре похоже на название пакетов в Java):
На самом деле, такой формат не является абсолютно обязательным. Достаточно, чтобы строка была уникальной. Но я рекомендую вам придерживаться принятых стандартов.
Создадим файл проекта (MyPlugin.pro
):
QT += core
QT -= gui
TARGET = MyPlugin
TEMPLATE = lib
CONFIG += plugin
DESTDIR = ../../bin/plugins/
SOURCES += myplugin.cpp
HEADERS += myplugin.h
INCLUDEPATH += ../include/
Конфигурация проекта напоминает обычную динамическую библиотеку. Ключевое отличие заключается в строке CONFIG += plugin
. Она указывает на то, что создаем мы именно плагин, а не что-то другое.
INCLUDEPATH
определен таким образом, чтобы мы смогли использовать myplugininterface.h
. Скомпонованный плагин будет помещен в DESTDIR
.
Заголовочный файл myplugin.h
:
#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include <myplugininterface.h>
class MyPlugin : public QObject, public MyPluginInterface {
Q_OBJECT
Q_INTERFACES( MyPluginInterface )
public:
~MyPlugin();
QString getString() const;
QVariant getVar() const;
};
#endif // MYPLUGIN_H
Три важных момента:
QObject
обязательно;Q_OBJECT
плагин работать не будет;Q_INTERFACES
явно указываются реализуемые интерфейсы.Соответствующая реализация (myplugin.cpp
):
Kra3.cc по материалам www.kra3.at-cc.ru.
#include "myplugin.h"
#include <QRect>
MyPlugin::~MyPlugin() {
}
QString MyPlugin::getString() const {
return "Hello, Plugin!";
}
QVariant MyPlugin::getVar() const {
return QRect( 10, 10, 500, 500 );
}
Q_EXPORT_PLUGIN2( MyPluginInterface, MyPlugin )
Главное: не забудьте экспортировать плагин с помощью макроса Q_EXPORT_PLUGIN2
.
Для подключения плагинов к Qt-приложению не нужно никаких особых настроек проекта. Создадим простое консольное Qt-приложение с таким main.cpp
:
#include <QDir>
#include <QPluginLoader>
#include <QDebug>
#include "myplugininterface.h"
int main() {
QDir pluginsDir( "./plugins" );
foreach( const QString& pluginName, pluginsDir.entryList( QDir::Files ) ) {
qDebug() << "===============================================================================";
qDebug() << "Found:" << pluginName;
QPluginLoader loader( pluginsDir.absoluteFilePath( pluginName ) );
if( loader.load() ) {
if( MyPluginInterface* myPlugin = qobject_cast< MyPluginInterface* >( loader.instance() ) ) {
qDebug() << "Testing: \n" <<
"(1)" << myPlugin->getString() << "\n" <<
"(2)" << myPlugin->getVar();
}
loader.unload();
} else {
qDebug() << "Failed to load :(";
qDebug() << loader.errorString();
}
qDebug() << "";
}
return 0;
}
Поиск плагинов осуществляется в цикле по содержимому каталога ./plugins
. Загрузить Qt-плагин можно с помощью QPluginLoader
.
Явно вызывать load()
не обязательно. Загрузка в любом случае произойдет при получении экземпляра экспортированного класса из плагина (функция-член instance()
).
Функция instance()
возвращает указатель на QObject
. Чтобы начать работу с плагином, требуется сделать приведение типа. Для этого используйте qobject_cast
.
Важно: не освобождайте память для созданного объекта. Если объект вам больше не нужен, то вызовите функцию unload()
. В этом случае плагин выгрузится из памяти со всеми созданными экземплярами.
Результат работы программы:
===============================================================================
Found: "libMyPlugin.so"
Testing:
(1) "Hello, Plugin!"
(2) QVariant(QRect, QRect(10,10 500x500) )
Рад слышать. Удачи! :)
ну чо ко так
Очень хотелось бы почитать про Qt Scripting, собственно, тоже как еще одно средство расширения функционала основного приложения…
overlapped:
Очень хотелось бы почитать про Qt Scripting, собственно, тоже как еще одно средство расширения функционала основного приложения…
К следующей неделе постараюсь подготовить вводную статью.
Спасибо, очень полезная информация.
Привет , такая ситуация , под архитектурой (32x) работает на ура , при переводе на (64x) ругается на строку Q_INTERFACES("имя интерфейса") с ошибкой Undefined interface . Не могу разобраться в чем дело . Подскажешь ?
Anonymous
Начинаю писать свой сайт. Очень полезная инфа.