1.简介
Qt插件是一种扩展机制,用于将应用程序的功能模块化,并且可以在运行时动态加载和卸载。Qt框架为插件提供了一套标准的接口和管理机制,使得插件的使用和集成变得简单和灵活,通过插件机制,可以将应用程序的功能划分为独立的可插拔的模块,使得应用程序更加可扩展和维护。
Qt插件系统具有以下特点:
- 动态加载:Qt插件是在运行时动态加载的,允许在不重新编译或重新启动应用程序的情况下添加或移除插件。
- 跨平台:Qt插件系统可以在不同的平台上运行,这意味着开发者可以使用相同的插件代码在Windows、macOS、Linux等多个操作系统上构建应用程序。
- 松耦合:通过使用插件系统,应用程序可以以松耦合的方式使用插件。插件之间可以独立开发,编译和测试,然后在运行时动态加载到应用程序中。
- 扩展性:Qt插件系统允许开发者根据应用程序的需求来设计和实现插件接口。这样,可以根据需要逐渐增加和扩展插件功能,而不会对应用程序的其他部分产生影响。
2.插件和动态库的区别
- 功能和用途:动态库是一种包含可执行代码和数据的库,可以通过链接器将其与应用程序静态或动态地链接在一起。而Qt插件是一种特殊类型的动态库,用于扩展和增强Qt应用程序的功能。
- API设计:动态库一般是一个完整的功能模块,可以直接调用其中的函数或使用其中的类。而Qt插件是基于插件接口或抽象类来设计的,通过继承插件接口并实现其纯虚函数来扩展插件的功能。
- 动态加载:动态库通常需要在应用程序编译时与之链接,并在运行时加载。而Qt插件则是在运行时动态加载,可以根据需要添加或移除插件,而无需重新编译或启动应用程序。
- 插件管理:Qt插件系统提供了更高级的插件管理功能,包括插件的自动发现、元信息的提取和注册、插件之间的依赖管理等。这使得使用和管理插件变得更加简单和灵活。
程序运行时需要动态库,否则运行不了,而插件不需要,在程序运行时动态加载。
3.如何创建插件
Qt提供了两个用于创建插件的API:
- 一个高级API,用于编写Qt本身的扩展:自定义数据库驱动程序、图像格式、文本编解码器、自定义样式等。
- 用于扩展Qt应用程序的低级API。
例如:如果您想编写一个自定义的QStyle子类并让Qt应用程序动态加载它,那么您可以使用更高级别的API。
编写一个扩展Qt本身的插件(高级API)是通过子类化适当的插件基类、实现一些函数和添加一个宏来实现的。
下表总结了插件基类,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 |
创建Qt本身的扩展:
如果你有一个名为MyStyle的新样式类,你想让它作为插件使用,那么这个类需要定义如下(mystyleplugin.h):
//.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()实现中使用了小写版本;大多数其他插件都是区分大小写的。
对于数据库驱动程序、图像格式、文本编解码器和大多数其他插件类型,不需要显式的对象创建。Qt将根据需要查找并创建它们。style是个例外,因为您可能希望在代码中显式地设置样式。要应用样式,请使用以下代码。
QApplication::setStyle(QStyleFactory::create("MyStyle"));
创建扩展Qt应用程序:
通过插件使应用程序可扩展包括以下步骤:
- 定义一组用于与插件对话的接口(仅具有纯虚拟函数的类)。
- 使用Q_DECLARE_INTERFACE()宏告诉Qt的元对象系统有关接口的信息。
- 在应用程序中使用QPluginLoader来加载插件。
- 使用qobject_cast()测试插件是否实现了给定的接口。
编写插件需要以下步骤:
- 声明一个从QObject和插件想要提供的接口继承的插件类。
- 使用Q_INTERFACES()宏告诉Qt的元对象系统有关接口的信息。
- 使用Q_plugin_METADATA()宏导出插件。
- 使用合适的.pro文件构建插件。
示例:
声明一个抽象接口类。
#ifndef COMPUTEINTERFACE_H
#define COMPUTEINTERFACE_H#include <QtPlugin>//定义接口
class ComputeInterface
{
public:virtual ~ComputeInterface() {}virtual int add(int a,int b) = 0;virtual int sub(int a,int b) = 0;
};#define ComputeInterface_iid "Test.Plugin.ComputeInterface" // 唯一标识符QT_BEGIN_NAMESPACE
Q_DECLARE_INTERFACE(ComputeInterface, ComputeInterface_iid)
QT_END_NAMESPACE#endif // COMPUTEINTERFACE_H
定义实现该接口的插件类。
#ifndef COMPUTEPLUGIN_H
#define COMPUTEPLUGIN_H#include <QObject>
#include "../MainWidget/computeinterface.h"class ComputePlugin : public QObject, public ComputeInterface
{Q_OBJECTQ_PLUGIN_METADATA(IID ComputeInterface_iid)Q_INTERFACES(ComputeInterface)
public:explicit ComputePlugin(QObject *parent = nullptr);virtual int add(int a,int b);virtual int sub(int a,int b);
};#endif // COMPUTEPLUGIN_H#include "computeplugin.h"ComputePlugin::ComputePlugin(QObject *parent): QObject(parent)
{}int ComputePlugin::add(int a, int b)
{return a+b;
}int ComputePlugin::sub(int a, int b)
{return a-b;
}
加载插件:
//加载exe所在目录下 plugin文件夹的所有插件QDir path = QDir(qApp->applicationDirPath());path.cd("../../plugins");foreach (QFileInfo info, path.entryInfoList(QDir::Files | QDir::NoDotAndDotDot)){QPluginLoader pluginLoader(info.absoluteFilePath());QObject *plugin = pluginLoader.instance();if (plugin){ComputeInterface *app = qobject_cast<ComputeInterface*>(plugin);if (app){int ret = app->add(1,2);qDebug()<<"ret = "<<ret;}}}
以下是工程目录结构:
4.完整工程
https://download.csdn.net/download/wzz953200463/88495546