• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    //-- 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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    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();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    第二步骤:另一个工程,写插件。这个工程编译出来的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了。
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    //-- 上述,主要的插件的接口已经写完了;下面我们要写 插件重要干些啥。(可能表述不准确,就是后面的东西是具体插件的功能的实现)
    也就是 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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    #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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

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

  • 相关阅读:
    Docker入门指南:基于 docker 搭建机器学习/深度学习开发环境
    element ui框架(嵌套路由)
    安装elasticsearch
    独辟蹊径:逆推Krpano切图算法,实现在浏览器切多层级瓦片图
    基于单片机微波炉加热箱系统设计
    知名外企嵌入式C语言笔试试题
    webpack 静态资源文件加载(assets)
    堆结构的深度理解
    面试SQL语句,学会这些就够了!!!
    【计算机组成原理】CRC码
  • 原文地址:https://blog.csdn.net/baidu_19552787/article/details/126901258