目录
一、编写插件步骤
1.1. 通过插件使应用程序可扩展涉及以下步骤:
- 定义一组用于与插件对话的接口(仅具有纯虚函数的类)。
- 使用Q_DECLARE_INTERFACE ()宏向Qt的元对象系统声明该接口。
- 在应用程序中使用QPluginLoader加载插件。
- 使用qobject_cast()测试插件是否实现了给定的接口。
1.2. 编写一个实现插件的步骤:
- 声明一个插件类,该类继承自QObject和该插件要提供的接口。
- 使用Q_INTERFACES ()宏告诉Qt的元对象系统有关接口的信息。
- 使用Q_PLUGIN_METADATA ()宏导出插件。
- 使用合适的.pro文件构建插件。
二、编写通过插件使应用程序可扩展
1. 新建一个子项目便于程序管理【文件->新建文件或项目->其它项目->子目录项目】
2. 名称随便命名即可,本次演示项目命名为【PluginProject】,然后指定目录
3. 指定构建套件默认即可
4.完成并添加应用程序项目
5.选择【Application->Qt Widgets Application】
6.本次演示应用程序命名为【MainApp】默认mainwindow窗口类
7.创建完成的项目结构如下,然后【MainApp右键->添加新的C++ Header File】命名为abstractinterface
8.定义一组用于与插件对话的接口(仅具有纯虚函数的类),使用Q_DECLARE_INTERFACE()宏向Qt的元对象系统声明该接口
#ifndef ABSTRACTINTERFACE_H
#define ABSTRACTINTERFACE_H
#include <QtPlugin>
class QWidget;
class AbstractInterface{
public:
virtual ~AbstractInterface(){} //必须定义虚析构函数
virtual QWidget* createWidgetPlugin(QWidget *parent) const = 0;
};
#define AbstarctInterface_IID "qt.org.com.abstactinterface/1.0" //iid随便命名当前项目独一无二即可
Q_DECLARE_INTERFACE(AbstractInterface,AbstarctInterface_IID) //声明接口
#endif // ABSTRACTINTERFACE_H
9.在mainwindow中使用QPluginLoader加载插件。使用qobject_cast()测试插件是否实现了给定的接口。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class AbstractInterface;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private:
void loadPlugin(); //应用程序装载插件
private:
AbstractInterface *mainInterface; //插件类
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "abstractinterface.h"
#include <QDir>
#include <QPluginLoader> //包含插件装载头文件
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
loadPlugin();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::loadPlugin()
{
//插件存放在应用程序目录下的plugin目录下,便于管理
QDir pluginDir(qApp->applicationDirPath()); //定位应用程序目录
if( pluginDir.cd("plugin") ) //进入plugin,前提先创建plugin目录
{
for(auto fileName:pluginDir.entryList(QDir::Files)) //遍历目录下的文件
{
QFileInfo info(fileName);
if(info.completeSuffix() == "dll" || info.completeSuffix() == "so") //过滤后缀为dll或so的动态库文件
{
QPluginLoader load(pluginDir.absoluteFilePath(fileName)); //装载插件
QObject *pluginObj = load.instance(); //获取插件根对象
if(pluginObj)
{
mainInterface = qobject_cast<AbstractInterface *>(pluginObj); //转换
mainInterface->createWidgetPlugin(ui->centralWidget);
}
}
}
}
}
三、编写一个实现插件
1.【PluginProject->右键->新子项目->Application->Qt Widgets Application】
2. 项目名为【PluginApp】基类选择QWidget
3.完成后的项目结构
4.把PluginApp.pro中的相关配置更改如下
TARGET = PluginApp
TEMPLATE =lib #template改app为lib
CONFIG += plugin #增加plugin的配置
DESTDIR = ../MainApp/debug/plugin #目标直接生成到MainApp的debug/plugin
INCLUDEPATH += ../MainApp #包含MainApp创建的abstractinterface.h
5.【PluginApp->右键->新增C++ Class】命名为InterfaceImplement,并继承QObject
6.接口实现类继承QObject以及抽象的AbstractInterface,使用Q_INTERFACES()宏告诉Qt的元对象系统有关接口的信息。使用Q_PLUGIN_METADATA ()宏导出插件。
#ifndef INTERFACEIMPLMENT_H
#define INTERFACEIMPLMENT_H
#include <QObject>
#include <abstractinterface.h>
class InterfaceImplment : public QObject, public AbstractInterface //集成抽象接口
{
Q_OBJECT
Q_INTERFACES(AbstractInterface) //实现的接口
Q_PLUGIN_METADATA(IID AbstarctInterface_IID) //导出接口后面的 FILE “jsonfile”可省略
public:
explicit InterfaceImplment(QObject *parent = nullptr);
~InterfaceImplment() Q_DECL_OVERRIDE;
QWidget *createWidgetPlugin(QWidget *parent) const Q_DECL_OVERRIDE;
};
#endif // INTERFACEIMPLMENT_H
7.构建PluginWidget对象,PluginWidget主要演示一个用户名和密码登录判断的简单示例
#include "interfaceimplment.h"
#include "pluginwidget.h" //包含plugwidget头文件
InterfaceImplment::InterfaceImplment(QObject *parent) : QObject(parent)
{
}
InterfaceImplment::~InterfaceImplment()
{
}
QWidget *InterfaceImplment::createWidgetPlugin(QWidget *parent) const
{
PluginWidget * w = new PluginWidget(parent); //返回PluginApp实现的界面类
return w;
}
8. 构建【PluginProject】项目,无错误将在MainApp/debug/plugin中生成PluginApp动态库,
然后单独运行MainAPP出现下面界面,表示插件扩展成功【在MainApp/debug中手动创建plugin文件夹】