Файл .pro для подключаемых модулей отличается от файлов .pro, используемых для приложений, поэтому мы покажем его состав:
TEMPLATE = lib
CONFIG += plugin
HEADERS = cursorhandler.h \
cursorplugin.h
SOURCES = cursorhandler.cpp \
cursorplugin.cpp
DESTDIR = $(QTDIR)/plugins/imageformats
По умолчанию файлы .pro используют шаблон app, но здесь мы должны указать шаблон lib, потому что подключаемый модуль является библиотекой, а не автономным приложением. Строка с элементом CONFIG указывает Qt на то, что у нас не простая библиотека, а библиотека подключаемого модуля. Элемент DESTDIR определяет каталог размещения подключаемого модуля. Каждый подключаемый модуль Qt должен находиться в соответствующем подкаталоге каталога plugins, и поскольку наш подключаемый модуль обеспечивает новый формат изображений, помещаем его в plugins/imageformats. Список имен каталогов и типов подключаемых модулей приводится на веб-странице http://doc.trolltech.com/4.1/plugins-howto.html. В данном случае мы предполагаем, что переменная среды QTDIR определяет каталог, в котором находится Qt.
Для Qt в рабочем (release) и отладочном (debug) режимах создаются различные подключаемые модули, поэтому, если установлены обе версии Qt, имеет смысл указать в файле .pro ту из них, которая будет использоваться, добавляя строку
CONFIG += release
Приложения, использующие подключаемые модули Qt, должны разворачиваться совместно со своими подключаемыми модулями. Подключаемые модули Qt должны располагаться в конкретных подкаталогах (например, в imageformats для форматов изображений). Приложения Qt ищут подключаемые модули в каталоге plugins, который располагается в каталоге размещения исполняемого модуля приложения, поэтому поиск подключаемых модулей изображений будет выполняться в application_dir/plugins/imageformats. Если требуется развернуть подключаемые модули Qt в другом каталоге, можно установить дополнительный путь поиска, используя функцию QCoreApplication::addLibraryPath().
Как обеспечить в приложении возможность подключения модулей
Подключаемый к приложению модуль является динамической библиотекой, которая реализует какой-нибудь один или несколько интерфейсов. Интерфейс — это класс, содержащий только чисто виртуальные функции. Связь между приложением и подключаемыми модулями осуществляется через виртуальную таблицу интерфейса. В этом разделе мы основное внимание уделим способам взаимодействия приложения Qt с подключаемым модулем через его интерфейсы, а в следующем разделе покажем, как можно реализовать подключаемый модуль.
Чтобы продемонстрировать конкретный пример, создадим простое приложение Text Art (искусство отображения текста), показанное на рис. 19.3. Специальные эффекты отображения текста обеспечиваются подключаемыми модулями; приложение получает список текстовых эффектов, создаваемых каждым подключаемым модулем, и проходит в цикле по этому списку, показывая результат каждого эффекта в соответствующем элементе списка QListWidget.
Рис. 19.3. Приложение Text Art.
В приложении Text Art определяется один интерфейс:
01 class TextArtInterface
02 {
03 public:
04 virtual ~TextArtInterface() { }
05 virtual QStringList effects() const = 0;
06 virtual QPixmap applyEffect(const QString &effect,
07 const QString &text,
08 const QFont &font,
09 const QSize &size,
10 const QPen &pen,
11 const QBrush &brush) = 0;
12 };
13 Q_DECLARE_INTERFACE(TextArtInterface,
14 "com.software-inc.TextArt.TextArtInterface/1.0")
В классе интерфейса обычно объявляются виртуальный деструктор, виртуальная функция, возвращающая список QStringList, и одна или несколько других виртуальных функций. Деструктор объявляется прежде всего для того, чтобы компилятор не жаловался на отсутствие виртуального деструктора в классе, который имеет виртуальные функции. В данном примере функция effects() возвращает список текстовых эффектов, которые могут создаваться подключаемым модулем. Этот список можно рассматривать как список ключей. При каждом вызове одной из функций мы передаем эти ключи в качестве первого аргумента, позволяя реализовать в одном подключаемом модуле несколько эффектов.