Qt 创建应用程序插件

27 篇文章 0 订阅
19 篇文章 0 订阅

前言

本文Qt中创建应用程序的插件主要有两方面:
一、创建插件
二、在应用程序中使用插件

一、创建插件

先用文字描述一下创建插件的主要步骤
①、首先新建一个插件的接口类,这个类只包含纯虚函数,这个纯虚函数是用于给接口类实现具体功能的。并在接口类中使用Q_DECLARE_INTERFACE()宏在Qt的元对象系统中注册该接口。
②、新建一个插件类,这个插件类一定要继承QObject 和①中新建好的接口类,并要求实现接口类的纯虚函数(即这个插件所需要实现的功能)。并使用 Q_PLUGIN_METADATA()宏导出插件、Q_INTERFACES()在Qt的元对象系统中注册该接口。
③、编写好.pro文件,用于编译构建生成.so文件。

下面具体代码实现创建插件
1、新建插件的接口类

//PluginInterface.h

#ifndef PLUGININTERFACE
#define PLUGININTERFACE

#include <QString>

class PluginInterface
{

public:
    virtual ~PluginInterface(){}
    virtual QString regexp(const QString &message) = 0;
};

Q_DECLARE_INTERFACE(PluginInterface,"pluginInterface") // Q_DECLARE_INTERFACE()在Qt元对象系统中注册了该接口,其中第一个参数为接口类名,第二个参数为一个字符串,用来确保这个接口与其他接口不相同

/*Q_DECLARE_INTERFACE 宏告诉Qt 这个纯虚类是一个插件接口类。
Q_DECLARE_INTERFACE 宏是与qobject_cast相关的。
第一个参数是接口类名,第二个参数是插件标志符,标识符是大小写敏感的且必须是唯一。*/

#endif // PLUGININTERFACE

2、新建插件类

// MyPlugin.h
#ifndef MYPPLUGIN_H
#define MYPPLUGIN_H

#include <QObject>
#include "plugininterface.h"
class MyPlugin:public QObject,PluginInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "myplugin")  //导出插件 (ps:Q_EXPORT_PLUGIN2()宏已经废弃,用时会报错,所以用Q_PLUGIN_METADATA()),第一个参数IID是必须的,同插件标识一样,而第二个参数FILE是可选的.
    Q_INTERFACES(PluginInterface)      //在Qt的元对象系统中注册该接口
public:
    QString regexp(const QString &message) Q_DECL_OVERRIDE;  // 实现接口类的纯虚函数,这里功能是输出字符串中出现的的第一个数字
};

/*
 Q_PLUGIN_METADATA  : Q_PLUGIN_METADATA  宏用于描述插件元数据,第一个参数 IID 是必须的,同插件标识符一样,
                      而第二个参数FILE是可选的,指定一个本地的 json 文件,该文件可以描述插件的相关数据信息。


Q_INTERFACES :若一个头文件或源文件中用到了 Q_INTERFACES 宏,那么在调用这个宏之前,
必须存在一个 Q_DECLARE_INTERFACE 宏声明相应的接口
(或者包含一个用 Q_DECLARE_INTERFACE 宏声明了该接口的头文件),
MOC会检查这一点,因为它在为 Q_INTERFACES 宏生成代码时要用到Q_DECLARE_INTERFACE 宏的 IID 参数。
Q_INTERFACES宏也是与qobject_cast相关,没有 Q_DECLARE_INTERFACE 和 Q_INTERFACES 这两个宏,
就无法对从插件中获取的实例指针进行qobject_cast映射

 Q_DECL_OVERRIDE :Q_DECL_OVERRIDE 宏来声明这是一个对虚函数进行定义的方法
 ,编译器会验证该方法名是否是父类中所有的,如果没有则报错(这个类似 Java里的 @Override 注解)。

*/


#endif // MYPPLUGIN_H
//myPlugin.cpp
#include "myPlugin.h"

#include <QRegExp>
#include <QtPlugin>


QString myPlugin::regexp(const QString &message)
{
    QRegExp rx("\\d+");
    rx.indexIn(message);
    QString str = rx.cap(0);
    return str;
}

3、配置.pro文件

HEADERS     += regexpplugin.h  regexpinterface.h  //用到的.h文件
SOURCES     += regexpplugin.cpp                   //用到的.cpp文件
TEMPLATE    =  lib                                //表明要构建的是库文件,而不是可执行文件(TEMPLATE =  app)
CONFIG      += plugin                             //告知qmake要创建一个插件
TARGET      =  mypplugin                          //生成库的名字 (mypplugin.so)
DESTDIR     =  ../plugins                         //生成库存放的位置

4、在项目中点击构建项目,这时可以看到plugins文件夹下生成了mypplugin.so文件了,这个就是插件,下面我们需要通过应用程序使用该插件来实现功能。

二、在应用程序中使用插件

应用程序主要实现的功能是:在QLineEdit中输入一段字符串,当点击一下QPushButton后,就会在QLabel中显示在字符串中出现的第一个数字。

//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "plugininterface.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:
    Ui::widget *ui;

    PluginInterface *pluginInterface;    
    bool loadPlugin();    // 加载插件
};

#endif // WIDGET_H
//widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPluginLoader>
#include <QMessageBox>
#include <QDir>
widget::widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::widget)
{
    ui->setupUi(this);

    if(!loadPlugin())   // 加载插件,如果插件加载不成功则显示提示框
    {
        QMessageBox::information(this,"Error","Could not load the plugin");
        ui->lineEdit->setEnabled(false);
        ui->pushButton->setEnabled(false);
    }
}

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

bool widget::loadPlugin()
{
    QDir pluginsDir("../plugins"); // 我的插件存放在 ../plugins目录下
    foreach(QString fileName,pluginsDir.entryList(QDir::Files))  // 便利目录下的所有普通文件
    {
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName)); //利用pluginLoader来加载插件
        QObject *plugin  = pluginLoader.instance();//返回插件的根组件对象。如果需要插件会被加载。如果无法加载插件,或者无法实例化根组件对象,则函数返回0。
        if(plugin)
        {
            regexpInterface = qobject_cast<PluginInterface *>(plugin);//测试插件是否实现了PluginInterface接口
            if(regexpInterface)  // 插件加载成功
                return true;
        }
    }
    return false;  // 没有插件或者插件加载失败
}

void widget::on_pushButton_clicked()
{
    QString str   = regexpInterface->regexp(ui->lineEdit->text());
    ui->labelNum->setText(str);
}

3、运行结果如下所示
这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值