Как создавать плагины Qt
Qt предоставляет два API для создания плагинов:
- API высокого уровня для написания расширений самого Qt: пользовательские драйверы баз данных, форматы изображений, кодеки текста, пользовательские стили и т. д.
- API низкого уровня для расширения приложений Qt.
Например, если вы хотите написать подкласс пользовательского QStyle и хотите, чтобы приложения Qt загружали его динамически, вы будете использовать API высокого уровня.
Поскольку API высокого уровня построен на основе API низкого уровня, некоторые проблемы характерны для обоих.
Если вы хотите предоставить плагины для использования с Qt Designer, см. документацию модуля Qt Designer.
Темы:
API высокого уровня: написание расширений Qt
Написание плагина, расширяющего сам Qt, достигается путем наследования от соответствующего базового класса плагина, реализации нескольких функций и добавления макроса.
Существует несколько базовых классов плагинов. Выводные плагины по умолчанию хранятся в подкаталогах стандартного каталога плагинов. Qt не найдёт плагины, если они не хранятся в соответствующем каталоге.
В следующей таблице обобщены базовые классы плагинов. Некоторые классы являются закрытыми и поэтому не документированы. Вы можете их использовать, но нет гарантии совместимости с будущими версиями Qt.
| Базовый класс | Имя каталога | Модуль Qt | Чувствительность к регистру ключа |
|---|---|---|---|
| QAccessibleBridgePlugin | accessiblebridge |
Qt GUI | Чувствителен к регистру |
| QImageIOPlugin | imageformats |
Qt GUI | Чувствителен к регистру |
| QPictureFormatPlugin (устаревший) | pictureformats |
Qt GUI | Чувствителен к регистру |
| QAudioSystemPlugin | audio |
Qt Multimedia | Нечувствителен к регистру |
| QDeclarativeVideoBackendFactoryInterface | video/declarativevideobackend |
Qt Multimedia | Нечувствителен к регистру |
| QGstBufferPoolPlugin | video/bufferpool |
Qt Multimedia | Нечувствителен к регистру |
| QMediaPlaylistIOPlugin | playlistformats |
Qt Multimedia | Нечувствителен к регистру |
| QMediaResourcePolicyPlugin | resourcepolicy |
Qt Multimedia | Нечувствителен к регистру |
| QMediaServiceProviderPlugin | mediaservice |
Qt Multimedia | Нечувствителен к регистру |
| QSGVideoNodeFactoryPlugin | video/videonode |
Qt Multimedia | Нечувствителен к регистру |
| QBearerEnginePlugin | bearer |
Qt Network | Чувствителен к регистру |
| QPlatformInputContextPlugin | platforminputcontexts |
Qt Platform Abstraction | Нечувствителен к регистру |
| QPlatformIntegrationPlugin | platforms |
Qt Platform Abstraction | Нечувствителен к регистру |
| QPlatformThemePlugin | platformthemes |
Qt Platform Abstraction | Нечувствителен к регистру |
| QGeoPositionInfoSourceFactory | position |
Qt Positioning | Чувствителен к регистру |
| QPlatformPrinterSupportPlugin | printsupport |
Qt Print Support | Нечувствителен к регистру |
| QSGContextPlugin | scenegraph |
Qt Quick | Чувствителен к регистру |
| QScriptExtensionPlugin | script |
Qt Script | Чувствителен к регистру |
| QSensorGesturePluginInterface | sensorgestures |
Qt Sensors | Чувствителен к регистру |
| QSensorPluginInterface | sensors |
Qt Sensors | Чувствителен к регистру |
| QSqlDriverPlugin | sqldrivers |
Qt SQL | Чувствителен к регистру |
| QIconEnginePlugin | iconengines |
Qt SVG | Нечувствителен к регистру |
| QAccessiblePlugin | accessible |
Qt Widgets | Чувствителен к регистру |
| QStylePlugin | styles |
Qt Widgets | Нечувствителен к регистру |
Если у вас есть новый класс стиля, называемый MyStyle, который вы хотите сделать доступным в качестве плагина, класс должен быть определен следующим образом (mystyleplugin.h):
class MyStylePlugin : public QStylePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "mystyleplugin.json")
public:
QStyle *create(const QString &key);
}; Убедитесь, что реализация класса находится в файле .cpp:
#include "mystyleplugin.h"
QStyle *MyStylePlugin::create(const QString &key)
{
if (key.toLower() == "mystyle")
return new MyStyle;
return 0;
} (Обратите внимание, что QStylePlugin нечувствителен к регистру, и в нашей реализации create() используется строка с нижним регистром; большинство других плагинов чувствительны к регистру.)
Кроме того, для большинства плагинов требуется файл json (mystyleplugin.json), содержащий метаданные, описывающие плагин. Для плагинов стиля он просто содержит список стилей, которые может создать плагин:
{ "Keys": [ "mystyleplugin" ] } Тип информации, который необходимо предоставить в файле json, зависит от плагина, пожалуйста, см. документацию класса для получения подробной информации о необходимой информации в файле.
Для драйверов баз данных, форматов изображений, кодировок текста и большинства других типов плагинов явного создания объектов не требуется. Qt найдет и создаст их по мере необходимости. Стиль является исключением, так как вы можете явно задать стиль в коде. Для применения стиля используйте такой код:
QApplication::setStyle(QStyleFactory::create("MyStyle")); Некоторые классы плагинов требуют реализации дополнительных функций. См. документацию класса для получения подробностей о виртуальных функциях, которые необходимо переопределить для каждого типа плагина.
Пример плагина стиля показывает, как реализовать плагин, расширяющий базовый класс QStylePlugin.
API низкого уровня: расширение приложений Qt
Не только сам Qt, но и приложения Qt могут быть расширены с помощью плагинов. Это требует, чтобы приложение обнаруживало и загружало плагины с помощью QPluginLoader. В этом контексте плагины могут предоставлять произвольную функциональность и не ограничены драйверами баз данных, форматами изображений, кодеками текста, стилями и другими типами плагинов, расширяющими функциональность Qt.
Для того чтобы приложение можно было расширить с помощью плагинов, необходимо выполнить следующие действия:
- Определите набор интерфейсов (классы только с чистыми виртуальными функциями), используемых для общения с плагинами.
- Используйте макрос Q_DECLARE_INTERFACE() для уведомления метаобъектной системы Qt об интерфейсе.
- Используйте QPluginLoader в приложении для загрузки плагинов.
- Используйте qobject_cast() для проверки, реализует ли плагин данный интерфейс.
Написание плагина включает в себя следующие шаги:
- Объявите класс плагина, который наследуется от QObject и от интерфейсов, которые плагин хочет предоставить.
- Используйте макрос Q_INTERFACES() для уведомления метаобъектной системы Qt об интерфейсах.
- Экспортируйте плагин с помощью макроса Q_PLUGIN_METADATA()
- Скомпилируйте плагин с помощью соответствующего файла
.pro.
Например, вот определение класса интерфейса:
class FilterInterface
{
public:
virtual ~FilterInterface() {}
virtual QStringList filters() const = 0;
virtual QImage filterImage(const QString &filter, const QImage &image,
QWidget *parent) = 0;
}; Вот определение класса плагина, который реализует этот интерфейс:
#include <QObject>
#include <QtPlugin>
#include <QStringList>
#include <QImage>
#include <plugandpaint/interfaces.h>
class ExtraFiltersPlugin : public QObject, public FilterInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.FilterInterface" FILE "extrafilters.json")
Q_INTERFACES(FilterInterface)
public:
QStringList filters() const;
QImage filterImage(const QString &filter, const QImage &image,
QWidget *parent);
}; Пример «Подключай и рисуй» подробно описывает этот процесс. Также см. Создание пользовательских виджетов для Qt Designer для получения информации о проблемах, специфичных для Qt Designer. Вы также можете взглянуть на Пример плагина «Эхо», который является более тривиальным примером того, как реализовать плагин, расширяющий приложения Qt. Обратите внимание, что QCoreApplication должен быть инициализирован до загрузки плагинов.
Поиск плагинов
Приложения Qt автоматически знают, какие плагины доступны, потому что плагины хранятся в стандартных подкаталогах плагинов. Из-за этого приложениям не нужен никакой код для поиска и загрузки плагинов, так как Qt обрабатывает их автоматически.
Во время разработки каталогом для плагинов является QTDIR/plugins (где QTDIR — каталог установки Qt), причём каждый тип плагина находится в подкаталоге для этого типа, например, styles. Если вы хотите, чтобы ваши приложения использовали плагины, и не хотите использовать стандартный путь к плагинам, пусть процесс установки определит нужный вам путь к плагинам и сохранит его, например, с помощью QSettings, чтобы приложение могло прочитать его при запуске. Затем приложение может вызвать QCoreApplication::addLibraryPath() с этим путем, и ваши плагины будут доступны приложению. Обратите внимание, что конечная часть пути (например, styles) не может быть изменена.
Если вы хотите, чтобы плагин загружался, один из подходов — создать подкаталог в приложении и поместить плагин в этот каталог. Если вы распространяете плагины, поставляемые с Qt (те, которые находятся в каталоге plugins), вы должны скопировать подкаталог в plugins, где находится плагин, в корневую папку вашего приложения (т.е. не включайте каталог plugins).
Для получения дополнительной информации о развертывании см. документацию по развертыванию приложений Qt и развертыванию плагинов.
Статические плагины
Обычный и наиболее гибкий способ включения плагина в приложение — скомпилировать его в динамическую библиотеку, которая поставляется отдельно и обнаруживается и загружается во время выполнения.
Плагины могут быть статически связаны с вашим приложением. Если вы собираете статическую версию Qt, это единственный вариант включения предопределенных плагинов Qt. Использование статических плагинов делает развертывание менее подверженным ошибкам, но имеет недостаток, что никакие функции из плагинов не могут быть добавлены без полной перекомпиляции и повторного распространения приложения.
Чтобы связать плагины статически, вам нужно добавить необходимые плагины в сборку, используя QTPLUGIN.
В файле .pro вашего приложения вам нужна следующая запись:
QTPLUGIN += qjpeg \
qgif \
qkrcodecs qmake автоматически добавляет плагины в QTPLUGIN, которые обычно необходимы модулям Qt (см. QT), в то время как более специализированные плагины необходимо добавлять вручную. Стандартный список автоматически добавляемых плагинов можно переопределить по типу. Например, чтобы связать минимальный плагин вместо стандартного плагина адаптации платформы Qt, используйте:
QTPLUGIN.platforms = qminimal
Если вы не хотите, чтобы автоматически подключались ни стандартный, ни минимальный плагин QPA, используйте:
QTPLUGIN.platforms = -
Стандартные значения настраиваются для оптимального опыта работы «из коробки», но могут необоснованно увеличивать размер приложения. Рекомендуется проверить командную строку компоновщика, сгенерированную qmake, и устранить ненужные плагины.
Подробное описание статической связи плагинов
Чтобы статические плагины действительно были связаны и инициализированы, также необходимы макросы Q_IMPORT_PLUGIN() в коде приложения, но они автоматически генерируются qmake и добавляются в ваш проект приложения.
Если вы не хотите, чтобы все плагины, добавленные в QTPLUGIN, были автоматически связаны, удалите import_plugins из переменной CONFIG:
CONFIG -= import_plugins
Создание статических плагинов
Также возможно создание собственных статических плагинов, следуя этим шагам:
- Добавьте
CONFIG += staticв файл.proвашего плагина. - Используйте макрос Q_IMPORT_PLUGIN() в вашем приложении.
- Используйте макрос Q_INIT_RESOURCE() в вашем приложении, если плагин содержит файлы qrc.
- Свяжите ваше приложение с вашей библиотекой плагина, используя
LIBSв файле.pro.
См. пример Plug & Paint и связанный с ним плагин Basic Tools для получения подробной информации об этом.
Примечание: Если вы не используете qmake для сборки плагина, вам необходимо убедиться, что макрос препроцессора QT_STATICPLUGIN определен.
Развертывание и отладка плагинов
Документ Развертывание плагинов описывает процесс развертывания плагинов с приложениями и их отладку при возникновении проблем.
См. также QPluginLoader, QLibrary и Пример Plug & Paint.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.12/plugins-howto.html