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