Как создать плагины 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.15/plugins-howto.html