Qt的插件怎么写

第一部分:在第一个工程中(宿主工程),写一个插件需要使用的头文件(接口类,没有直接实现的.cpp)

#ifndef ABSTRACTINTERFACE_H
#define ABSTRACTINTERFACE_H

#include 
class QWidget;

class AbstractInterface
{
public:
    virtual ~AbstractInterface() {}

    //-- 由于我想创建的插件是带有UI的,所以类型是QWidget
    virtual QWidget *createPluginWidget(QWidget *parent) = 0;
    virtual void testFunc() = 0;
};

#define AbstractInterface_iid "Welcome to pay attention to the public number"
Q_DECLARE_INTERFACE(AbstractInterface, AbstractInterface_iid)


#endif // ABSTRACTINTERFACE_H

//-- https://baijiahao.baidu.com/s?id=1652356608638861677&wfr=spider&for=pc
//-- 上次我们是直接在Qt 自带的例子基础上做的修改,直接运行。我们的插件需要继承Qt 的Style插件,之后重新实现自己想要实现的部分。在主程序中直接通过QApplication::setStyle进行调用。

//-- 下面开展我们本次的内容,官方文档说明
//-- 通过插件不仅可以扩展Qt本身,而且可以扩展Qt应用程序。
//-- 这要求应用程序使用QPluginLoader检测和加载插件。 在这种情况下,插件可以提供任意功能,并且不仅限于数据库驱动程序,图像格式,文本编解码器,样式以及扩展Qt功能的其他类型的插件。

// 1. 通过插件使应用程序可扩展涉及以下步骤(应用程序扩展插件步骤):
// * ①编写仅具有纯虚函数的类.即定义一组用于与插件对话的接口(仅具有纯虚函数的类)。
// * ②使用Q_DECLARE_INTERFACE ()宏向Qt的元对象系统声明该接口。该宏就是向 Qt 元对象系统注册一下我写的这个接口。
// * “注册”是什么意思?就是登记呗。我在 Qt 的花名册上写下我的名字,那 Qt 从此就认识我了。该宏的第一个参数是接口类的名字,第二个参数是 iid(相当于一个身份证信息,可以随便写个字符串)。
// *
// * 此时 “通过插件使应用程序可以被扩展” 的前两步就完成了,后面两步之后在宿主程序中加载插件时再介绍。

//至此,我的程序给外界提供了个公共接口,并且为了 Qt 编程方便还向元对象系统注册了一下。
//以后所有的插件都通过这个接口来扩展 app 的功能,当然也可以写更多的接口供外界调用。

后面两步来了,看代码。
在宿主程序中,运行加载插件。
widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include "abstractinterface.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private slots:
    void on_pushButton_clicked();

private:
    bool loadPlugin();
private:
    Ui::Widget *ui;

    //本宿主程序中有一个AbstractInterface对象
    AbstractInterface * m_pluginInterface;
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include "QDir"
#include 
//宿主程序加载插件:在应用程序中使用QPluginLoader加载插件
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    loadPlugin();
}

Widget::~Widget()
{
    delete ui;
}

//-- 运行时加载插件
bool Widget::loadPlugin()
{
    QDir pluginsDir(qApp->applicationDirPath());
    qDebug() << qApp->applicationDirPath() << endl;
    //遍历PluginWidget目录下的文件,如果实例化成功则使用qobject_cast()测试插件是否实现了给定的接口。【应用程序扩展插件步骤的③和④】
    foreach(QString fileName, pluginsDir.entryList(QDir::Files)) {

        //-- ③在应用程序中使用QPluginLoader加载插件。
        //QPluginLoader 加载插件名
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
         qDebug() << fileName << endl;

         //-- ④使用qobject_cast()测试插件是否实现了给定的接口
        //获取 QObject 示例;
        QObject *plugin = pluginLoader.instance();
        //转化成接口指针,然后判断不为空即为正常加载。
        if(plugin)
        {
            //--  在那个项目里有个 AbstractInterface 接口类。我的主程序里是有这个指针的.
            m_pluginInterface = qobject_cast<AbstractInterface *>(plugin);
            if(m_pluginInterface)
            {
                //-- 完成插件的调用
                m_pluginInterface->testFunc();
                //m_pluginInterface->createPluginWidget(ui->pluginWidget)->show();
                m_pluginInterface->createPluginWidget(NULL)->show();
            }
        }
    }
}

void Widget::on_pushButton_clicked()
{
     m_pluginInterface->createPluginWidget(NULL)->show();
}

main.cpp

#include "widget.h"
#include 
#include "widget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

第二步骤:另一个工程,写插件。这个工程编译出来的dll 文件可以放到合适位置,用于提供给宿主程序加载(即宿主程序加载插件)。

//-- 利用插件类的头文件也称为(接口类),继承这个接口类,进而进行实现。
myfirstplugin.h 继承接口类,并在元对象系统注册,他是一个插件库。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include "abstractinterface.h"

//-- MainWidget的app提供了接口,那么插件当然就是要使用这个接口

//(1)继承这个接口和 QObject。继承接口这个好理解,继承 QObject 是为了使用 Qt 的元对象系统;
class MyFirstPlugin : public QObject, public AbstractInterface
{
    Q_OBJECT

public:
    explicit MyFirstPlugin(QWidget *parent = 0);
    ~MyFirstPlugin();

    //-- (2)使用Q_INTERFACES ()宏告诉Qt的元对象系统有关接口的信息,告诉元对象系统“我要用这个接口”;
    Q_INTERFACES(AbstractInterface)
    //-- (3)使用Q_PLUGIN_METADATA ()宏导出插件   (4)pro 文件中添加“CONFIG += plugin”
    Q_PLUGIN_METADATA(IID "Welcome to pay attention to the public number." FILE "myfirstplugin.json")
    //-- Qt4的导出
    //Q_EXPORT_PLUGIN2(pluginName,class);

    QWidget * createPluginWidget(QWidget *parent);
    void testFunc();
};

#endif // MAINWINDOW_H


// * 插件编写步骤
// * ①声明一个插件类,该类继承自QObject和该插件要提供的接口
// * ②使用Q_INTERFACES ()宏告诉Qt的元对象系统有关接口的信息
// * ③使用Q_PLUGIN_METADATA ()宏导出插件。
// * ④使用合适的.pro文件构建插件。即pro 文件中添加“CONFIG += plugin” 。
// * 在myfirstplugin.h中无法直接包含abstractinterface.h,这时需要修改PluginWidget.pro。
// * 根据创建的目录添加INCLUDEPATH += ../MainWidget,这时就可以include abstractinterface.h了。


myfirstplugin.cpp 实现这个继承接口的 类,在纯虚函数中,做我们要想 具体想要 干啥的事情。(我这里就是返回一个widget,还有打印字符串)

#include "myfirstplugin.h"
#include "ui_pluginWidget.h"
#include "pluginwidget.h"
#include "QDebug"

MyFirstPlugin::MyFirstPlugin(QWidget *parent) :
    QObject(parent)
{
}

MyFirstPlugin::~MyFirstPlugin()
{
   // delete ui;
}

QWidget *MyFirstPlugin::createPluginWidget(QWidget *parent)
{

    PluginWidget *pluginWidget = new PluginWidget(parent);

    return pluginWidget;

}

void MyFirstPlugin::testFunc()
{
    qDebug() << "this is PluginWodget" << endl;
}

//-- 上述,主要的插件的接口已经写完了;下面我们要写 插件重要干些啥。(可能表述不准确,就是后面的东西是具体插件的功能的实现)
也就是 pluginWidget 对象。和插件关系不大了。

这里就是一个普通的UI

#ifndef PLUGINWIDGET_H
#define PLUGINWIDGET_H

#include 

namespace Ui {
class PluginWidget;
}

class PluginWidget : public QWidget
{
    Q_OBJECT

public:
    explicit PluginWidget(QWidget *parent = 0);
    ~PluginWidget();

private:
    Ui::PluginWidget *ui;
};

#endif // PLUGINWIDGET_H

#include "pluginwidget.h"
#include "ui_pluginwidget.h"

PluginWidget::PluginWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PluginWidget)
{
    ui->setupUi(this);
}

PluginWidget::~PluginWidget()
{
    delete ui;
}

自己瞎总结:就是宿主程序 怎么去加载插件的问题。

  1. 接口类声明+元对象系统注册
  2. 宿主程序如果想 加载插件,则利用pluginLoader 和 AbstractInterface * m_pluginInterface; 的多态性,实现在宿主程序中插件的加载。
    就是宿主程序,去一些路径下找dll文件。 找到后pluginLoader 加载到内存。
  3. 写插件,告诉Qt的元对象系统有关接口的信息,我要用这个接口, 我要到处插件,然后对1中的接口类 进行实现, 并在接口中 完成自己想要的功能。

Qt的插件 主要就是 接口类和实现接口类的类的 元对象系统注册的问题。
其它都是c++中的特性。 比如利用多态,纯抽象类、纯抽象类的实现。

你可能感兴趣的:(qt,qt,ui,开发语言)