[Qt插件]-02创建应用程序插件(插件化开发的一种思路)

本篇是学习Qt Creator快速入门,插件开发的笔记
 
分为两部分
  1. 创建插件
  2. 使用插件的应用程序(测试插件)
 
插件是被使用的应用程序加载使用的。 是使用插件的应用程序定义接口,插件按照接口来实现。
有几个需要注意的宏,其他的都是常规的CPP代码
 
1.创建插件
 
创建一个插件包括以下几步:
①定义一个插件类,它需要同时继承自QObject类和该插件所提供的功能对应的接口类;
②使用Q_INTERFACES()宏在Qt的元对象系统中注册该接口;
③使用Q_PLUGIN_METADATA()宏导出该插件;
④使用合适的.pro文件构建该插件。
 
 
2.使用插件的应用程序
 
使一个应用程序可以通过插件进行扩展要进行以下几步:
①定义一组接口(只有纯虚函数的抽象类);
②使用Q_DECLARE_INTERFACE()宏在Qt的元对象系统中注册该接口;
③在应用程序中使用QPluginLoader来加载插件;
④使用qobject_cast()来测试插件是否实现了给定的接口。
 
注意事项: 使用插件的应用程序想要正常运行,需要先编译插件项目(生成插件嘛)
 
动手实践
 
下面通过一个小demo来学习这个知识。
这里需要创建两个项目,一个项目用来生成插件,即dll/so文件;另一个项目是一个测试程序,用来使用插件。
因为这两个项目中有共用的文件,所以这里将它们放同一个文件夹下,目录结构如下:
myplugin
----plugin (插件项目)
----plugins (存放生成的插件)
----regexpwindow (使用插件的项目(测试项目))
 
创建插件
创建一个空的qmake项目。Add New添加C++类RegExpPlugin
----plugin.pro
----regexpplugin.h
----regexpplugin.cpp
----myplugin.json
 
plugin.pro
TARGET = regexppligin
TEMPLATE = lib
CONFIG += plugin
DESTDIR = ../plugins
INCLUDEPATH += ../regexpwindow
HEADERS +=
regexpplugin.h
SOURCES +=
regexpplugin.cpp
 
 
myplugin.json
{}
 
regexpplugin.h
 1 #ifndef REGEXPPLUGIN_H
 2 #define REGEXPPLUGIN_H
 3  
 4 #include <QObject>
 5 #include "regexpinterface.h"
 6  
 7 class RegExpPlugin : public QObject,RegExpInterface
 8 {
 9 Q_OBJECT
10 Q_PLUGIN_METADATA(IID "org.qter.Example.myplugin.RexExpInterface"
11 FILE "myplugin.json")
12 Q_INTERFACES(RegExpInterface)
13  
14 public:
15 QString regexp(const QString &message)override;
16 };
17  
18 #endif // REGEXPPLUGIN_H
 
regexpplugin.cpp
#include "regexpplugin.h"
#include <QRegExp>
#include <QtPlugin>
 
QString RegExpPlugin::regexp(const QString &message)
{
QRegExp rx("\d+");
rx.indexIn(message);
QString str = rx.cap(0);
return str;
}
说明:
为了使这个类作为一个插件,它需要同时继承自QObject和RegExpInterface.
RegExpInterface是接口类,用来指明插件要实现的功能,其在regexpinterface.h文件
中定义。这个接口由使用它的程序设计。因为插件是为了扩展原有的程序嘛。
 
Q_PLUGIN_METADATA()宏用于声明插件的元数据:
其中必须指明IID标识符,标识符是一个字符串,必须保证它的唯一性;
FILE指定一个JSON格式的插件元数据文件,该参数是可选的,其命名一般使用项目名称即可,内容一般只包含一组大括号。
这里还需要使用Q_INTERFACES()宏将这个接口注册到Qt的元对象系统中,告知Qt这个类实现了哪个接口。
 
测试插件的程序


 
regexpinterface.h //定义接口,这个类中只能包含纯虚函数。
#ifndef REGEXPINTERFACE_H
#define REGEXPINTERFACE_H
 
#include <QString>
 
class RegExpInterface{
 
public:
virtual ~RegExpInterface(){}
virtual QString regexp(const QString &message) = 0;
};
 
//这个是写在类外面的。浪费了好大一会时间。
Q_DECLARE_INTERFACE(RegExpInterface,
"org.qter.Example.myplugin.RexExpInterface")
 
#endif // REGEXPINTERFACE_H
 
说明:
使用Q_DECLARE_INTERFACE()宏在Qt元对象系统中注册了该接口,其中第二个参数就是前面指定的IID。
 
 
widget.h // 加载插件
 
引入 #include "regexpinterface.h"
private:
RegExpInterface *regexpinterface_;
bool loadPlugin();
 
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","");
        ui->lineEdit->setEnabled(false);
        ui->pushButton->setEnabled(false);
    }
}

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

/**
 * @brief Widget::loadPlugin
 * @return
 */
bool Widget::loadPlugin(){

    QDir pluginsDir("../plugins");
    // 遍历插件目录
    for (QString fileName : pluginsDir.entryList(QDir::Files)) {
        QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin =  loader.instance();
        if(plugin){
            regexpinterface_ =  qobject_cast<RegExpInterface *>(plugin);
            if(regexpinterface_){
                return true;
            }
        }
    }

    return false;
}

void Widget::on_pushButton_clicked()
{
    QString str = regexpinterface_->regexp(ui->lineEdit->text());
    ui->label_num->setText(str);
}
编译plugin 然后在运行regexpwindow 
 
完!
 
 
 
 
 
原文地址:https://www.cnblogs.com/__tudou__/p/12957199.html