Как создать плагины 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);
}; Пример Plug & Paint подробно объясняет этот процесс. Также см. Создание пользовательских виджетов для Qt Designer для получения информации о проблемах, которые специфичны для Qt Designer. Вы также можете взглянуть на Пример плагина Echo, который является более простым примером того, как реализовать плагин, который расширяет приложения 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.14/plugins-howto.html