14 "com.software-inc.TextArt.TextArtInterface/1.0")
В классе интерфейса обычно объявляются виртуальный деструктор, виртуальная функция, возвращающая список QStringList, и одна или несколько других виртуальных функций. Деструктор объявляется прежде всего для того, чтобы компилятор не жаловался на отсутствие виртуального деструктора в классе, который имеет виртуальные функции. В данном примере функция effects() возвращает список текстовых эффектов, которые могут создаваться подключаемым модулем. Этот список можно рассматривать как список ключей. При каждом вызове одной из функций мы передаем эти ключи в качестве первого аргумента, позволяя реализовать в одном подключаемом модуле несколько эффектов.
В конце мы используем макрос Q_DECLARE_INTERFACE() для назначения некоторого идентификатора интерфейсу. Этот идентификатор обычно имеет четыре компонента: инвертированное имя домена, определяющее создателя интерфейса, имя приложения, имя интерфейса и номер версии. При любом изменении интерфейса (например, при добавлении новой виртуальной функции или при изменении сигнатуры существующей функции) мы должны не забыть увеличить номер версии; в противном случае приложение может завершиться аварийно при попытке получения доступа к старой версии подключаемого модуля.
Это приложение реализуется в виде класса TextArtDialog. Мы будем показывать только тот программный код, который связан с применением подключаемых модулей. Давайте начнем с конструктора:
01 TextArtDialog::TextArtDialog(const QString &text, QWidget *parent)
02 : QDialog(parent)
03 {
04 listWidget = new QListWidget;
05 listWidget->setViewMode(QListWidget::IconMode);
06 listWidget->setMovement(QListWidget::Static);
07 listWidget->setIconSize(QSize(260, 80));
08 …
09 loadPlugins();
10 populateListWidget(text);
11 …
12 }
Конструктор создает виджет QListWidget, содержащий список доступных эффектов. Он вызывает закрытую функцию loadPlugins() для поиска и загрузки всех подключаемых модулей, реализующих интерфейс TextArtInterface, и заполняет список виджетов с помощью вызова другой закрытой функции — populateListWidget().
01 void TextArtDialog::loadPlugins()
02 {
03 QDir pluginDir(QApplication::applicationDirPath());
04 #if defined(Q_OS_WIN)
05 if (pluginDir.dirName().toLower() == "debug"
06 || pluginDir.dirName().toLower() == "release")
07 pluginDir.cdUp();
08 #elif defined(Q_OS_MAC)
09 if (pluginDir.dirName() == "MacOS") {
10 pluginDir.cdUp();
11 pluginDir.cdUp();
12 pluginDir.cdUp();
13 }
14 #endif
15 if (!pluginDir.cd("plugins"))
16 return;
17 foreach (QString fileName, pluginDir.entryList(QDir::Files)) {
18 QPluginLoader loader(pluginDir.absoluteFilePath(fileName));
19 if (TextArtInterface *interface =
20 qobject_cast(loader.instance()))
21 interfaces.append(interface);
22 }
23 }
В функции loadPlugins() мы пытаемся загрузить все файлы, находящиеся в каталоге приложения plugins. (В Windows исполняемый модуль приложения обычно находится в подкаталоге debug или release, поэтому поднимаемся на один каталог выше. В Mac OS X учитываем структуру группового каталога (bundle directory).)