Как создавать плагины 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).
Дополнительную информацию о развертывании см. в документации Развертывание приложений 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.13/plugins-howto.html