Qt 為創建插件提供瞭 2 個 API:
例如:若想要編寫自定義 QStyle 子類並讓 Qt 應用程序動態加載它,將使用更高級 API。
由於更高級 API 建立在更低級 API 之上,因此有一些問題是兩者公共的。
If you want to provide plugins for use with Qt Designer, see 創建自定義 Widget 插件 .
編寫擴展 Qt 本身的插件是通過子類化適當插件基類、實現一些函數、及添加宏達成的。
有幾個插件基類。默認情況下,派生插件存儲在標準插件目錄的子目錄下。Qt 將找不到插件,若未將它們存儲在適當目錄下。
下錶匯總瞭插件基類。某些類是私有的,因此未文檔化。可以使用它們,但不承諾兼容更高 Qt 版本。
| 基類 | 目錄名 | Qt 模塊 | 鍵區分大小寫 |
|---|---|---|---|
| QAccessibleBridgePlugin |
accessiblebridge
|
Qt GUI | 區分大小寫 |
| QImageIOPlugin |
imageformats
|
Qt GUI | 區分大小寫 |
| QPictureFormatPlugin (obsolete) |
pictureformats
|
Qt GUI | 區分大小寫 |
| QBearerEnginePlugin |
bearer
|
Qt Network | 區分大小寫 |
| QPlatformInputContextPlugin |
platforminputcontexts
|
Qt Platform Abstraction | 不區分大小寫 |
| QPlatformIntegrationPlugin |
platforms
|
Qt Platform Abstraction | 不區分大小寫 |
| QPlatformThemePlugin |
platformthemes
|
Qt Platform Abstraction | 不區分大小寫 |
| QPlatformPrinterSupportPlugin |
printsupport
|
Qt Print Support | 不區分大小寫 |
| QSGContextPlugin |
scenegraph
|
Qt Quick | 區分大小寫 |
| QSqlDriverPlugin |
sqldrivers
|
Qt SQL | 區分大小寫 |
| QIconEnginePlugin |
iconengines
|
Qt SVG | 不區分大小寫 |
| QAccessiblePlugin |
accessible
|
Qt Widgets | 區分大小寫 |
| QStylePlugin |
styles
|
Qt Widgets | 不區分大小寫 |
If you have a new document viewer class called
JsonViewer
想要將其用作插件,則需要按以下方式定義類 (
jsonviewer.h
):
class JsonViewer : public ViewerInterface { Q_OBJECT Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface/1.0" FILE "jsonviewer.json") Q_INTERFACES(ViewerInterface) public: JsonViewer(); ~JsonViewer() override; private: bool openJsonFile(); QTreeView *m_tree; QListWidget *m_toplevel = nullptr; QJsonDocument m_root; QPointer<QLineEdit> m_searchKey; };
確保類實現位於
.cpp
文件:
JsonViewer::JsonViewer() { connect(this, &AbstractViewer::uiInitialized, this, &JsonViewer::setupJsonUi); } void JsonViewer::init(QFile *file, QWidget *parent, QMainWindow *mainWindow) { AbstractViewer::init(file, new QTreeView(parent), mainWindow); m_tree = qobject_cast<QTreeView *>(widget()); }
此外,JSON 文件 (
jsonviewer.json
) containing meta data describing the plugin is required for most plugins. For document viewer plugins it simply contains the name of the viewer plugin.
{ "Keys": [ "jsonviewer" ] }
The type of information that needs to be provided in the json file is plugin dependent. See the class documentation for details on the information that needs to be contained in the file.
For database drivers, image formats, text codecs, and most other plugin types, no explicit object creation is required. Qt will find and create them as required.
Plugin classes may require additional functions to be implemented. See the class documentation for details of the virtual functions that must be reimplemented for each type of plugin.
The Document Viewer Demo shows how to implement a plugin that displayes structured contents of a file. Each plugin therefore reimplements virtual functions, which
QString viewerName() const override { return QLatin1StringView(staticMetaObject.className()); };
QStringList supportedMimeTypes() const override;
bool hasContent() const override;
bool supportsOverview() const override { return true; }
In addition to Qt itself, Qt applications can be extended through plugins. This requires the application to detect and load plugins using QPluginLoader . In that context, plugins may provide arbitrary functionality and are not limited to database drivers, image formats, text codecs, styles, and other types of plugins that extend Qt's functionality.
透過插件使應用程序可擴展,涉及以下步驟:
編寫插件涉及這些步驟:
例如,這裏是接口類的定義:
class ViewerInterface : public AbstractViewer { public: virtual ~ViewerInterface() = default; };
Here's the interface declaration:
#define ViewerInterface_iid "org.qt-project.Qt.Examples.DocumentViewer.ViewerInterface/1.0" Q_DECLARE_INTERFACE(ViewerInterface, ViewerInterface_iid)
另請參閱 為 Qt Widgets Designer 創建自定義 Widgets for information about issues that are specific to Qt Widgets Designer.
Qt applications automatically know which plugins are available, because plugins are stored in the standard plugin subdirectories. Because of this, applications don't require any code to find and load plugins, since Qt handles them automatically.
在開發期間,插件目錄為
QTDIR/plugins
(在哪裏
QTDIR
是 Qt 的安裝目錄),各種類型的插件在該類型的子目錄下,例如,
styles
。若想要應用程序使用插件但又不想使用標準插件路徑,讓安裝進程確定想要使用的插件路徑並保存路徑,例如,通過使用
QSettings
,供應用程序運行時讀取。然後,應用程序可以調用
QCoreApplication::addLibraryPath
() 采用此路徑,您的插件將可用於應用程序。注意,最後部分的路徑 (例如,
styles
) 無法更改。
If you want the plugin to be loadable, one approach is to create a subdirectory under the application, and place the plugin in that directory. If you distribute any of the plugins that come with Qt (the ones located in the
plugins
目錄),必須拷貝其子目錄在
plugins
插件,位於應用程序根文件夾下 (即:不包括
plugins
目錄)。
有關部署的更多信息,見 部署 Qt 應用程序 and 部署插件 文檔編製。
將插件包括在應用程序中的正常且最靈活方式,是將其編譯成單獨隨附的動態庫,並在運行時檢測並加載。
可以將插件靜態鏈接到應用程序。若構建靜態版本的 Qt,這是包括 Qt 預定義插件的唯一選項。使用靜態插件可使部署不易齣錯,但有缺點:無法添加插件功能,當不完整重新構建和重新分發應用程序時。
CMake and qmake automatically add the plugins that are typically needed by the Qt modules that are used, while more specialized plugins need to be added manually. The default list of automatically added plugins can be overridden per type.
The defaults are tuned towards an optimal out-of-the-box experience, but may unnecessarily bloat the application. It is recommended to inspect the linker command line and eliminate unnecessary plugins.
為促使實際鏈接並實例化靜態插件, Q_IMPORT_PLUGIN () macros are also needed in application code, but those are automatically generated by the build system and added to your application project.
To statically link plugins in a CMake project, you need to call the qt_import_plugins 命令。
例如,Linux
libinput
plugin is not imported by default. The following command imports it:
qt_import_plugins(myapp INCLUDE Qt::QLibInputPlugin)
To link the minimal platform integration plugin instead of the default Qt platform adaptation plugin, use:
qt_import_plugins(myapp
INCLUDE_BY_TYPE platforms Qt::MinimalIntegrationPlugin
)
Another typical use case is to link only a certain set of
imageformats
plugins:
qt_import_plugins(myapp
INCLUDE_BY_TYPE imageformats Qt::QJpegPlugin Qt::QGifPlugin
)
If you want to prevent the linking of any
imageformats
plugin, use:
qt_import_plugins(myapp
EXCLUDE_BY_TYPE imageformats
)
If you want to turn off the addition of any default plugin, use the
NO_DEFAULT
option of
qt_import_plugins
.
In a qmake project, you need to add the required plugins to your build using
QTPLUGIN
:
QTPLUGIN += qlibinputplugin
For example, to link the minimal plugin instead of the default Qt platform adaptation plugin, use:
QTPLUGIN.platforms = qminimal
若不想鏈接默認,也不想自動鏈接 minimal QPA 插件,使用:
QTPLUGIN.platforms = -
若不想要添加到 QTPLUGIN 的所有插件被自動鏈接,移除
import_plugins
從
CONFIG
變量:
CONFIG -= import_plugins
It is also possible to create your own static plugins by following these steps:
STATIC
選項到
qt_add_plugin
command in your
CMakeLists.txt
. For a qmake project, add
CONFIG += static
到插件的
.pro
文件。
CMakeLists.txt
or
LIBS
在您的
.pro
文件。
見 插件和描繪 範例和關聯的 基本工具 插件,瞭解如何做到這的有關細節。
注意:
If you are not using CMake or qmake to build your plugin, you need to make sure that the
QT_STATICPLUGIN
預處理器宏有定義。
Plugin types (static or shared) and operating systems require specific approaches to locate and load plugins. It's useful to implement an abstraction for loading plugins.
void ViewerFactory::loadViewerPlugins() { if (!m_viewers.isEmpty()) return;
QPluginLoader::staticInstances () 返迴 QObjectList with a pointer to each statically linked plugin
// Load static plugins
const QObjectList &staticPlugins = QPluginLoader::staticInstances();
for (auto *plugin : staticPlugins)
addViewer(plugin);
Shared plugins reside in their deployment directories, which may require OS-specific handling.
// Load shared plugins
QDir pluginsDir = QDir(QApplication::applicationDirPath());
#if defined(Q_OS_WINDOWS)
pluginsDir.cd("app"_L1);
#elif defined(Q_OS_DARWIN)
if (pluginsDir.dirName() == "MacOS"_L1) {
pluginsDir.cdUp();
pluginsDir.cdUp();
pluginsDir.cdUp();
}
#endif
const auto entryList = pluginsDir.entryList(QDir::Files);
for (const QString &fileName : entryList) {
QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = loader.instance();
if (plugin)
addViewer(plugin);
#if 0
else
qDebug() << loader.errorString();
#endif
}
}
The 部署插件 文檔涵蓋采用應用程序部署插件和調試它們 (當齣現問題時) 的過程。
另請參閱 QPluginLoader and QLibrary .