概述
Qt提供了两个用于创建插件的api:
- 一个高级API,用于编写Qt本身的扩展:自定义数据库驱动程序,图像格式,文本编解码器,自定义样式等。
- 用于扩展Qt应用程序的低级API。
例如,如果您想编写一个自定义的QStyle子类并让Qt应用程序动态加载它,那么您将使用高级的API。
由于高级API构建在低级API之上,因此有些问题对两者都是通用的。
如果你想为Qt Designer提供插件,请参阅Qt Designer模块文档。
高级API:编写Qt扩展
通过继承适当的插件基类、实现一些函数和添加宏,可以编写扩展Qt本身的插件。
有几个插件基类。派生插件默认存储在标准插件目录的子目录中。如果插件没有存储在适当的目录中,Qt将无法找到它们。
下表总结了插件基类。有些类是私有的,因此没有在文档中记录。你可以使用它们,但不能保证与以后的Qt版本兼容。
Base Class | Directory Name | Qt Module | Key Case Sensitivity |
---|---|---|---|
QAccessibleBridgePlugin | accessiblebridge | Qt GUI | Case Sensitive |
QImageIOPlugin | imageformats | Qt GUI | Case Sensitive |
QPictureFormatPlugin (obsolete) | pictureformats | Qt GUI | Case Sensitive |
QAudioSystemPlugin | audio | Qt Multimedia | Case Insensitive |
QDeclarativeVideoBackendFactoryInterface | video/declarativevideobackend | Qt Multimedia | Case Insensitive |
QGstBufferPoolPlugin | video/bufferpool | Qt Multimedia | Case Insensitive |
QMediaPlaylistIOPlugin | playlistformats | Qt Multimedia | Case Insensitive |
QMediaResourcePolicyPlugin | resourcepolicy | Qt Multimedia | Case Insensitive |
QMediaServiceProviderPlugin | mediaservice | Qt Multimedia | Case Insensitive |
QSGVideoNodeFactoryPlugin | video/videonode | Qt Multimedia | Case Insensitive |
QBearerEnginePlugin | bearer | Qt Network | Case Sensitive |
QPlatformInputContextPlugin | platforminputcontexts | Qt Platform Abstraction | Case Insensitive |
QPlatformIntegrationPlugin | platforms | Qt Platform Abstraction | Case Insensitive |
QPlatformThemePlugin | platformthemes | Qt Platform Abstraction | Case Insensitive |
QGeoPositionInfoSourceFactory | position | Qt Positioning | Case Sensitive |
QPlatformPrinterSupportPlugin | printsupport | Qt Print Support | Case Insensitive |
QSGContextPlugin | scenegraph | Qt Quick | Case Sensitive |
QScriptExtensionPlugin | script | Qt Script | Case Sensitive |
QSensorGesturePluginInterface | sensorgestures | Qt Sensors | Case Sensitive |
QSensorPluginInterface | sensors | Qt Sensors | Case Sensitive |
QSqlDriverPlugin | sqldrivers | Qt SQL | Case Sensitive |
QIconEnginePlugin | iconengines | Qt SVG | Case Insensitive |
QAccessiblePlugin | accessible | Qt Widgets | Case Sensitive |
QStylePlugin | styles | Qt Widgets | Case Insensitive |
如果你有一个新的样式类MyStyle,你想让它作为一个插件可用,类需要定义如下(mystyleplugin.h):
class MyStylePlugin : public QStylePlugin
{Q_OBJECTQ_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()实现中使用小写版本的键;大多数其他插件是区分大小写的。)
此外,大多数插件都需要一个json文件(mystyleplugin.json),其中包含描述插件的元数据。对于样式插件,它只是包含一个可以由插件创建的样式列表:
{ "Keys": [ "mystyleplugin" ] }
json文件中需要提供的信息类型依赖于插件,请参阅类文档了解文件中需要包含的信息的详细信息。
对于数据库驱动程序、图像格式、文本编解码器和大多数其他插件类型,不需要显式地创建对象。Qt会根据需要找到并创建它们。样式是个例外,因为你可能想在代码中显式地设置样式。要应用样式,请使用如下代码:
QApplication::setStyle(QStyleFactory::create("MyStyle"));
一些插件类需要实现额外的函数。请参阅类文档了解必须为每种类型的插件重新实现的虚函数的详细信息。
样式插件示例展示了如何实现扩展QStylePlugin基类的插件。
低级API:扩展Qt应用程序
不仅Qt本身可以通过插件进行扩展,Qt应用程序也可以通过插件进行扩展。这要求应用程序使用QPluginLoader检测和加载插件。在这种情况下,插件可以提供任意功能,而且不限于数据库驱动、图像格式、文本编解码器、样式和其他扩展Qt功能的插件。
通过插件使应用程序具有可扩展性涉及以下步骤。
- 定义一组用于与插件通信的接口(只有纯虚函数的类)。
- 使用Q_DECLARE_INTERFACE()宏告诉Qt的元对象系统有关接口的信息。
- 在应用程序中使用QPluginLoader加载插件。
- 使用qobject_cast()测试插件是否实现了给定的接口。
编写插件需要以下步骤。
- 声明一个插件类,它继承QObject和插件想要提供的接口。
- 使用Q_INTERFACES()宏告诉Qt的元对象系统有关接口的信息。
- 使用Q_PLUGIN_METADATA()宏导出插件。
- 使用合适的。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_OBJECTQ_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);
};
Plug & Paint示例文档详细解释了这个过程。关于Qt Designer特有的问题的信息,请参见为Qt Designer创建自定义小部件。你也可以看一看Echo插件示例,这是一个关于如何实现扩展Qt应用程序的插件的更简单的示例。请注意,在加载插件之前,必须初始化QCoreApplication。
加载插件
Qt应用程序自动知道哪些插件可用,因为插件存储在标准的插件子目录中。因为这个应用程序不需要任何代码来查找和加载插件,因为Qt会自动处理它们。
在开发过程中,插件的目录是QTDIR/plugins(其中QTDIR是Qt安装的目录),每种类型的插件都有一个对应类型的子目录,例如styles。如果希望应用程序使用插件,而不想使用标准的插件路径,请让安装过程确定插件要使用的路径,并保存该路径,例如通过使用QSettings,以便应用程序在运行时读取。然后应用程序可以使用此路径调用QCoreApplication::addLibraryPath(),你的插件将对应用程序可用。注意,路径的最后一部分(例如styles)不能更改。
如果你希望插件是可加载的,那么一种方法是在应用程序下创建一个子目录,并将插件放在该目录中。如果发布任何Qt附带的插件(位于plugins目录下的那些),必须将插件所在的plugins子目录复制到应用程序根目录下(即不包含plugins目录)。
有关部署的更多信息,请参阅部署Qt应用程序和部署插件的文档。
静态插件
在应用程序中包含插件的常规和最灵活的方式是将其编译为单独发布的动态库,并在运行时检测和加载。
插件可以静态链接到应用程序中。如果构建的是静态版本的Qt,这是包含Qt预定义插件的唯一选择。使用静态插件使部署不那么容易出错,但有一个缺点,即在不完全重新构建和重新分发应用程序的情况下,无法添加来自插件的功能。
要静态链接插件,需要使用QTPLUGIN将所需的插件添加到构建中。
在你的应用程序的.pro文件中,你需要以下条目:
QTPLUGIN += qjpeg \qgif \qkrcodecs
qmake会自动向QTPLUGIN中添加Qt模块通常需要的插件(参见Qt),而更专业的插件需要手动添加。每个类型都可以覆盖自动添加插件的默认列表。例如,要链接最小插件而不是默认的Qt平台适配插件,请使用:
QTPLUGIN.platforms = qminimal
如果你既不想默认的,也不想最小的QPA插件被自动链接,使用:
QTPLUGIN.platforms = -
默认值被调优为最佳的开箱即用体验,但可能会不必要地增加应用程序的体积。建议检查由qmake构建的链接器命令行,并删除不必要的插件
链接静态插件的详细信息
为了使静态插件真正被链接和实例化,应用程序代码中还需要Q_IMPORT_PLUGIN()宏,但这些宏是由qmake自动生成并添加到应用程序项目中的。
如果你不希望所有添加到QTPLUGIN的插件都自动链接,从CONFIG变量中删除import_plugins:
CONFIG -= import_plugins
创建静态插件
你也可以按照以下步骤创建自己的静态插件。
- 将CONFIG += static添加到插件的.pro文件中。
- 在应用程序中使用Q_IMPORT_PLUGIN()宏。
- 如果插件提供qrc文件,请在应用程序中使用Q_INIT_RESOURCE()宏。
- 在。pro文件中使用LIBS链接应用程序和插件库。
有关如何做到这一点的详细信息,请参阅Plug & Paint示例和相关的基本工具插件。
注意:如果您不使用qmake来构建插件,则需要确保定义了QT_STATICPLUGIN预处理器宏。
部署和调试插件
部署插件文档涵盖了使用应用程序部署插件并在出现问题时调试插件的过程。
See also QPluginLoader, QLibrary, and Plug & Paint Example.
How to Create Qt Plugins | Qt 5.15