Qt插件之创建应用程序插件

创建一个插件时,要先创建一个接口,接口就是一个类,它只包含纯虚函数。插件类要继承自该接口。插件类存储在一个共享库中, 因此可 以在应用程序运行时进行加载。创建一个 插件包括分三个部分:

1、插件类     2、插件接口    3、调用插件

所以分为以下几步:

  1. 定 义一个插件类,它需要同时继承自 QObject 类和该插件所提供的功能对应的接口类
  2. 用 QJNTERFACESO宏在 Qt 的元对象 系统中注册该接口;
  3. 用 Q_PLUGIN_METADATA()宏声明该插件;
  4. 修改插件的. pro 文件构建该插件编译生成dll。/* 此时插件类部分完成  到应用程序部分中加载dll */
  5. 定义一组接口(只有纯虚函数的抽象类)
  6. 用 Q_DECLARE_INTERFACE()宏在 Qt 的元对象 系统中注册该接口;
  7. 应 用程序中使用 QPluginLoader 来加载插件;
  8. 用 qobject_cast()来测试插件是否实现了给定的接口

上代码

插件类:

新建一个空的项目:New Project->其他项目->Empty qmake Project

添加自定义的项目名,此时我的是PlugApp_1

添加一个C++的类,名称为myPlugin,内容为

myPlugin.h  

其实的myplugin.json随意设置一个内容为空的文件即可 

#ifndef MYPLUGIN_H
#define MYPLUGIN_H

#include <QObject>
#include "widgetPluginTest/plugininterface.h"

/* 1、创建一个插件类,它需要同时继承自QObject类和该插件所提供的功能对应的接口类 */
class myPlugin : public QObject,PluginInterface
{
public:
    Q_OBJECT
    /* 2、在Qt的元对象系统中注册该接口 */
    Q_INTERFACES(PluginInterface)

    /* 3、声明该插件的元数据,其实必须指明IID标识符,标识符必须保证它的唯一性 */
    Q_PLUGIN_METADATA(IID "qt.myplugin.test" FILE "myplugin.json")
    /* 4、声明了一个 print 函数, 它是在 PluginInterface 中定 义的一个纯虚函数。 这里通过重写 它来实现该插件具体的功能*/
    void print(const QString &message);
};

#endif // MYPLUGIN_H

myPlugin.c

#include "myplugin.h"
#include <QtPlugin>
#include <QDebug>
void myPlugin::print(const QString &message)
{
    qDebug() << "login print,message: " << message;
}

PlugApp_1.pro

TEMPLATE = lib /* 表明该项目要构建 库文件 */
CONFIG += plugin /* 告知 qmake 要创建一个 插件 */ 
HEADERS += \
    myplugin.h

SOURCES += \
    myplugin.cpp
INCLUDEPATH += wingetPluginTest /* 插件接口类的路径添加到INCLUDEPATH */  
TARGET = myplugin /* TARGET 指定了产生的 dll 文件的 名字 */ 
DESTDIR = plugins /* DESTDIR 指定了生成的 dll 文件所在的目录 */ 

插件类已经结束了,使 用插件扩展应用程序

第一步,新建 Qt Widgets 应用。项目名称为 widgetPluginTest选择路径时仍选择前面建立的 PlugApp_1 目录。基类选择 QWidgetÿ类名保持 Widget 不变。建立完成后,向该项目中添加新文件,模 板选择 C++头文件,名 称为 PluginInterface.h
第二步,定义接口。将 PluginInterface. h 文件的内容更 改如下:

#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H

#include <QString>
/* 这个类只能包含纯虚函数 */
class PluginInterface
{

public:
    virtual ~PluginInterface() {}
    virtual void print(const QString &message) = 0;
};
/*  Qt 元对象系统中注册了该接口 */
Q_DECLARE_INTERFACE(PluginInterface,"qt.myplugin.test")
#endif // PLUGININTERFACE_H

第三步,编写调用插件应用程序 

widget.h中

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "plugininterface.h"
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    PluginInterface *myPluginInterface;
    bool loadPlugin();
};

#endif // WIDGET_H

widget.c中

#include "widget.h"
#include <QPluginLoader>
#include <QMessageBox>
#include <QDir>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    if (!loadPlugin()) { // 如果无法加载插件
        QMessageBox::information(this, "Error", "Could not load the plugin");
    }
}

Widget::~Widget()
{

}

bool Widget::loadPlugin()
{
    QDir pluginsDir("../plugins");

    // 遍历插件目录
    foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
        /* 2.3、在应用程序中使用pluginLoader来加载插件 */
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
        qDebug() << fileName;
        QObject *plugin = pluginLoader.instance();
        if (plugin) {
            /* 2.4、测试插件是否实现了给定的接口 */
            myPluginInterface = qobject_cast<PluginInterface *>(plugin);
            if (myPluginInterface){
                myPluginInterface->print("hello world!!!");
                return true;
            }
            pluginLoader.unload();
        }
    }
    return false;
}

第四步,运行程序。 先构建 myplugin 项目,在 编辑模式左侧项目列 表中的 myplugin 目录上右击,在弹出的级联菜单中选择“ 构建”。构建完成后,会生成plugins 目录,里面包含了生成的 dll 文件。然后运行应用程序 
注:Qt文档中说明,QPluginLoader 释放之后,其获取到的插件不会释放,所以,需要手动 delete 插件,或者使用 unload() 方法释放。

Qt的插件系统归根到底还是 dll 的动态调用时获取其中的类那一招,dll只可以导出函数,不可以导出指针,但是为了能得到dll中的类,可以导出一个接口,使用接口获取对象指针。但是在dll的调用一方,却无法识别获取到的类指针,所以利用C++的多态和继承的特性来完成。使用抽象类,声明好抽象接口,将需要导出的类继承自该抽象类,并实现其声明的接口。dll的导出方和调用方公用一个抽象类声明文件,在dll导出函数内部,利用多态,将抽象的类指针new成子类对象,并返回出来,则调用方就可以识别得到的类指针了。

发布了121 篇原创文章 · 获赞 38 · 访问量 8万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览