Как создать подключаемые модули Qt (Qt plugins)
Qt предлагает два API для создания подключаемых модулей (plugins) :
Например, если вы хотите написать собственный подкласс QStyle и заставить приложение на Qt загружать его динамически, вы будете использовать высокоуровневое API. Так как высокоуровневое API построено на низкоуровневом API, некоторые особенности общие для обоих. Если вы хотите предоставить подключаемые модули для использования вместе с Qt Designer, смотрите документацию модуля QtDesigner. Темы:
Высокоуровневое API: Написание расширений для QtНаписание подключаемого модуля, который расширяет Qt, достигается наследованием соответствующего базового класса подключаемого модуля, реализацией нескольких функции, и добавлением макроса. Есть несколько базовых классов подключаемых модулей. Вторичные подключаемые модули, по умолчанию, хранятся в подкаталогах стандартного каталога подключаемых модулей. Qt не найдет подключаемые модули, если они не хранятся в правильном каталоге.
Но где находится каталог plugins? Когда приложение запущено, Qt сначала просматривает каталог исполняемого файла приложения в качестве pluginsbase. Например, если приложение находится в C:\Program Files\MyApp и имеет подключаемый модуль стиля, Qt будет искать в C:\Program Files\MyApp\styles. (Смотрите QCoreApplication::applicationDirPath(), что бы выяснить, где находится исполняемый файл приложения). Qt так же будет смотреть в каталоге указанном в QLibraryInfo::location(QLibraryInfo::PluginsPath), который обычно расположен в QTDIR/plugins (где QTDIR это каталог, где установлена Qt). Если вы хотите, чтобы Qt просматривала в дополнительных местах, вы можете добавить столько путей, сколько необходимо, вызвав QCoreApplication::addLibraryPath(). И, если вы хотите установить собственный путь или пути, вы можете использовать QCoreApplication::setLibraryPaths(). Вы так же можете использовать файл qt.conf для переопределения жестко зашитых путей, которые вкомпилированы в библиотеку Qt. Для получения дополнительной информации, смотрите документацию Использование qt.conf. Еще один способ, это установить переменную окружения QT_PLUGIN_PATH перед запуском приложения. Если установлена, Qt будет искать подключаемые модули в путях (разделенных системным разделителем путей) указанных в переменной. Предположим, что у вас есть новый класс стиля, названый MyStyle, который вы хотите сделать доступным в качестве подключаемого модуля. Требуемый код очень простой, вот объявление класса (mystyleplugin.h): class MyStylePlugin : public QStylePlugin { public: QStringList keys() const; QStyle *create(const QString &key); }; Убедитесь, что реализация класса расположена в файле .cpp (включая объявление класса): #include "mystyleplugin.h" QStringList MyStylePlugin::keys() const { return QStringList() << "MyStyle"; } QStyle *MyStylePlugin::create(const QString &key) { if (key.toLower() == "mystyle") return new MyStyle; return 0; } Q_EXPORT_PLUGIN2(pnp_mystyleplugin, MyStylePlugin) (Заметьте, что QStylePlugin не чувствителен к регистру и использована прописная версия ключа в нашей реализации create(); большинство других подключаемых модулей чувствительны к регистру.) Для драйверов баз данных, форматов изображений, текстовых кодеков и большинства других типов подключаемых модулей, не требуется явное создание объекта. Qt найдет и создаст их как требуется. Исключением являются стили, так как вы можете хотеть установить стиль в коде, явно. Чтобы добавить стиль, используйте следующий код: QApplication::setStyle(QStyleFactory::create("MyStyle")); Некоторые классы подключаемых модулей требуют реализации дополнительных функций. За подробностями о виртуальных функциях, которые должны быть переопределены для каждого типа подключаемого модуля, обращайтесь к документации классов. Приложения на Qt автоматически знают какие подключаемые модули доступны, так как они хранятся в стандартных каталогах подключаемых модулей. Из-за этого приложению не требуется код для поиска и загрузки подключаемых модулей, так как Qt управляет ими автоматически. Каталог по умолчанию для подключаемых модулей это QTDIR/plugins (где QTDIR это каталог, где установлена Qt), с подкаталогом для каждого типа подключаемых модулей, например, styles. Если вы хотите, чтобы ваше приложение использовало подключаемые модули и вы не хотите использовать стандартный путь к подключаемым модулям, заставьте ваш инсталляционный процесс определить путь, который вы хотите использовать для подключаемых модулей и сохраните его, например, используя QSettings, для считывания приложением при запуске. Приложение может вызвать QCoreApplication::addLibraryPath() с этим путем и ваши подключаемые модули будут доступны приложению. Заметьте, что последняя часть пути (например, styles) не может быть изменена. Обычный способ, добавить подключаемый модуль в приложение - это скомпилировать его с приложением, или скомпилировать его в динамическую библиотеку и использовать ее как любую другую. Если вы хотите, чтобы подключаемый модуль был загружаемым, тогда единственный подход - это создать подкаталог в папке с программой и положить подключаемый модуль в этот каталог. Для получения дополнительной информации относительно развертывания, смотрите документацию Развертывание приложений на Qt. Пример Style Plugin показывает как реализовать подключаемый модуль, который расширяет базовый класс QStylePlugin. Низкоуровневое API: Расширение приложений на QtНе только сама Qt, но так же приложения на Qt могут быть расширены с помощью подключаемых модулей. Это требует от приложения обнаружить и загрузить подключаемые модули используя QPluginLoader. В этом случае, подключаемые модули могут предоставлять произвольную функциональность и не ограничены драйверами баз данных, форматами изображений, текстовыми кодеками, стилями, и другими типами подключаемых модулей, которые расширяют функциональность Qt. Создание расширяемых с помощью подключаемых модулей приложений включает следующие шаги:
Написание подключаемого модуля включает следующие шаги:
Например, вот определение интерфейсного класса: class FilterInterface { public: virtual ~FilterInterface() {} virtual QStringList filters() const = 0; virtual QImage filterImage(const QString &filter, const QImage &image, QWidget *parent) = 0; }; Q_DECLARE_INTERFACE(FilterInterface, "com.trolltech.PlugAndPaint.FilterInterface/1.0") Вот определение класса подключаемого модуля, который реализует этот интерфейс: #include <QObject> #include <QStringList> #include <QImage> #include <plugandpaint/interfaces.h> class ExtraFiltersPlugin : public QObject, public FilterInterface { Q_OBJECT Q_INTERFACES(FilterInterface) public: QStringList filters() const; QImage filterImage(const QString &filter, const QImage &image, QWidget *parent); }; Документация примера "Plug & Paint" объясняет этот процесс в подробностях. Смотрите также Создание собственных виджетов для Qt Designer, для получения информации о проблемах, специфичных для Qt Designer. Вы можете так же взглянуть на Пример "Echo Plugin" - наиболее простой пример того, как реализовать подключаемый модуль, расширяющий приложение на Qt. Динамическая загрузка и проверка подключаемых модулейПри загрузке подключаемых модулей библиотека Qt делает некоторые санитарные проверки, чтобы определить может ли подключаемый модуль быть загружен и использован или нет. Это предоставляет возможность иметь множество версий и конфигураций библиотеки Qt, установленных рядом.
При сборке подключаемых модулей, расширяющих приложение, важно убедиться, что подключаемый модуль сконфигурирован так же как и приложение. Это значит, что если приложение было собрано в режиме релиза, подключаемый модуль так же должен быть собран в режиме релиза. Если вы конфигурируете Qt для сборки и в режиме релиза и в режиме отладки, но собираете приложение только в режиме релиза, вы должны убедиться, что ваши подключаемые модули так же собираются в режиме релиза. По умолчанию, если доступна отладочная сборка Qt, подключаемые модули будут собраны только в режиме отладки. Что бы заставить подключаемые модули собираться в режиме релиза, добавьте следующую строку в файл проекта подключаемого модуля: CONFIG += release Это гарантирует совместимость подключаемого модуля с версией библиотеки, используемой в приложении. Ключ сборкиПри загрузке подключаемого модуля Qt сверяет ключ сборки каждого подключаемого модуля со своим, что бы убедиться, что только совместимые подключаемые модули загружены; любые подключаемые модули, которые сконфигурированы иначе загружены не будут. Ключ сборки содержит следующую информацию:
С целью отладки возможно обходить проверку ключа сборки во времени выполнения установив переменную окружения QT_NO_PLUGIN_CHECK равной ненулевому значению в окружении, в котором ваше приложение запускается. Статические подключаемые модулиПодключаемые модули могут быть слинкованы статически вместе с приложением. Если вы соберете статическую версию Qt, то возможно включение только предопределенных подключаемых модулей Qt. Когда компилируется как статическая библиотека, тогда Qt предоставляет следующие статические подключаемые модули:
Чтобы линковать статически вместе с этими подключаемыми модулями, вам необходимо использовать макрос Q_IMPORT_PLUGIN() в своем приложении и вам необходимо добавить требуемые подключаемые модули к вашей сборке используя QTPLUGIN. Например, в вашем main.cpp: #include <QApplication> #include <QtPlugin> Q_IMPORT_PLUGIN(qjpeg) Q_IMPORT_PLUGIN(qgif) Q_IMPORT_PLUGIN(qkrcodecs) int main(int argc, char *argv[]) { QApplication app(argc, argv); ... return app.exec(); } В .pro-файле вашего приложения, вам необходимо добавить следующую запись: QTPLUGIN += qjpeg \ qgif \ qkrcodecs Так же возможно создать свой собственный статический подключаемый модуль, следуя этим шагам:
За подробностями, как это сделать, обращайтесь к примеру Plug & Paint и связанным с ним подключаемым модулем Basic Tools. Кэш подключаемых модулейДля того, чтобы ускорить загрузку и проверку подключаемых модулей, некоторая информация, собираемая при загрузке подключаемого модуля, кэшируется с помощью QSettings. Это включает информацию о том, был ли подключаемый модуль удачно загружен или нет, так что последующая операция загрузки не будет пытаться загрузить неправильный подключаемый модуль. Тем не менее, если поменяется "время последнего изменения" подключаемого модуля, запись в кэше считается устаревшей и подключаемый модуль загружается независимо от значений в кэше, которые обновляются в соответствии с новым результатом. Это так же означает, что штамп времени должен быть обновлён каждый раз, когда подключаемый модуль или любой зависимый ресурс (такой как общая библиотека) были обновлены, так как зависимый ресурс может влиять на результат загрузки подключаемого модуля. Иногда при разработке подключаемых модулей необходимо удалить записи из кэша подключаемых модулей. С тех пор как Qt использует QSettings для управления кэшем подключаемых модулей, размещение подключаемых модулей платформозависимо; для получения дополнительной информации о каждой платформе, смотрите документацию по QSettings. Например, в Windows записи хранятся в реестре и пути для каждого подключаемого модуля обычно начинаются с одной из этих двух строк: HKEY_CURRENT_USER\Software\Trolltech\OrganizationDefaults\Qt Plugin Cache 4.2.debug HKEY_CURRENT_USER\Software\Trolltech\OrganizationDefaults\Qt Plugin Cache 4.2.false Отладка подключаемых модулейЕсть несколько проблем, которые могут помешать корректно написанным подключаемым модулем работать с приложением, спроектированным для их использования. Многие из них связаны с различиями в способе сборки приложений и подключаемых модулей, часто возникая из-за разных систем сборок и процессов. Следующая таблица содержит описание общих причин проблем, с которыми сталкиваются разработчики при создании подключаемых модулей:
Вы можете так же использовать переменную окружения QT_DEBUG_PLUGINS для получения диагностической информации из Qt о каждом подключаемом модуле, который она пытается загрузить. Установите эту переменную в любое не-нулевое значение, в окружении, из которого запускается ваше приложение. Смотрите также QPluginLoader, QLibrary, и Plug & Paint Example.
|
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |