如何创建 Qt 插件

Qt 为创建插件提供了 2 个 API:

  • 用于编写 Qt 自身扩展的高级 API:自定义数据库驱动程序、图像格式、文本编解码器、自定义风格、等。
  • 用于扩展 Qt 应用程序的低级 API。

例如:若想要编写自定义 QStyle 子类并让 Qt 应用程序动态加载它,将使用更高级 API。

由于更高级 API 建立在更低级 API 之上,因此有一些问题是两者公共的。

若想要提供用于 Qt Designer 的插件,见 Qt Designer 模块文档编制。

话题:

高级 API:编写 Qt 扩展

编写扩展 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 不区分大小写

若有新样式类称为 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 () implementation; most other plugins are case sensitive.)

此外,JSON 文件 ( mystyleplugin.json ) 包含大多数插件所需的插件描述元数据。对于样式插件,它仅仅包含可以由插件创建的样式列表:

{ "Keys": [ "mystyleplugin" ] }
					

在 JSON 文件中需要提供的信息类型取决于插件,请参阅类文档编制了解在文件中需要包含信息的有关细节。

对于数据库驱动程序、图像格式、文本编解码器及大多数其它插件类型,明确创建对象不是必需的。Qt 将根据需要查找并创建它们。样式例外,由于可能想要在代码中明确设置样式。要应用样式,使用代码像这样:

QApplication::setStyle(QStyleFactory::create("MyStyle"));
					

某些插件类要求实现其它功能。见类文档编制,了解各插件类型必须重实现的虚函数的有关细节。

The 样式插件范例 shows如何实现插件以扩展 QStylePlugin 基类。

低级 API:扩展 Qt 应用程序

不只 Qt 本身,Qt 应用程序还可以被扩展透过插件。这要求应用程序检测并加载插件,使用 QPluginLoader 。在这种情况下,插件可以提供任意功能,不限于数据库驱动程序、图像格式、文本编解码器、样式及扩展 Qt 功能的其它类型插件。

透过插件使应用程序可扩展,涉及以下步骤:

  1. 定义一组用于对话插件的接口 (仅具有纯虚函数的类)。
  2. 使用 Q_DECLARE_INTERFACE () 宏告诉 Qt 的 元对象系统 关于接口。
  3. 使用 QPluginLoader 在应用程序中加载插件。
  4. 使用 qobject_cast () 测试插件是否有实现给定接口。

编写插件涉及这些步骤:

  1. 声明插件类继承 QObject 及插件想要提供的接口。
  2. 使用 Q_INTERFACES () 宏告诉 Qt 的 元对象系统 关于接口。
  3. 导出插件使用 Q_PLUGIN_METADATA () 宏。
  4. 构建插件使用合适 .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);
};
					

The 插件和描绘 范例文档编制会详细阐述此过程。另请参阅 创建自定义 Widget 为 Qt Designer 了解 Qt Designer 特定问题的有关信息。还可以查看 回显插件范例 ,这是有关如何实现扩展 Qt 应用程序插件的更通俗范例。请注意: QCoreApplication 必须已初始化,在可以加载插件之前。

定位插件

Qt 应用程序自动知道哪些插件可用,因为插件存储在标准插件子目录下。应用程序不要求采用任何代码查找和加载插件,由于 Qt 会自动处理它们。

在开发期间,插件目录为 QTDIR/plugins (在哪里 QTDIR 是 Qt 的安装目录),各种类型的插件在该类型的子目录下,例如, styles 。若想要应用程序使用插件但又不想使用标准插件路径,让安装进程确定想要使用的插件路径并保存路径,例如,通过使用 QSettings ,供应用程序运行时读取。然后,应用程序可以调用 QCoreApplication::addLibraryPath () 采用此路径,您的插件将可用于应用程序。注意,最后部分的路径 (例如, styles ) 无法更改。

若想要插件可加载,一种途径是在应用程序下创建子目录,并将插件放置于该目录下。若分发 Qt 自带的任何插件 (其位于 plugins 目录),必须拷贝其子目录在 plugins 插件,位于应用程序根文件夹下 (即:不包括 plugins 目录)。

有关部署的更多信息,见 部署 Qt 应用程序 and 部署插件 文档编制。

静态插件

将插件包括在应用程序中的正常且最灵活方式,是将其编译成单独随附的动态库,并在运行时检测并加载。

可以将插件静态链接到应用程序。若构建静态版本的 Qt,这是包括 Qt 预定义插件的唯一选项。使用静态插件可使部署不易出错,但有缺点:无法添加插件功能,当不完整重新构建和重新分发应用程序时。

CMake and qmake automatically add the plugins that are typically needed by the Qt modules 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.

在 CMake 中导入静态插件

To statically link plugins in a CMake project, you need to call the qt_import_plugins 命令。

For example, the 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 .

在 qmake 中导入静态插件

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
					

创建静态插件

创建自己的静态插件也是可能的,通过以下这些步骤:

  1. 传递 STATIC 选项到 qt_add_plugin command in your CMakeLists.txt . For a qmake project, add CONFIG += static 到插件的 .pro 文件。
  2. 使用 Q_IMPORT_PLUGIN () 宏在应用程序中。
  3. 使用 Q_INIT_RESOURCE () 宏在应用程序中,若插件随附 qrc 文件。
  4. 链接应用程序与插件库,使用 target_link_libraries 在您的 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 预处理器宏有定义。

部署和调试插件

The 部署插件 文档涵盖采用应用程序部署插件和调试它们 (当出现问题时) 的过程。

另请参阅 QPluginLoader , QLibrary ,和 插件和描绘范例 .