zoukankan      html  css  js  c++  java
  • [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 
     
    完!
     
     
     
     
     
  • 相关阅读:
    查找算法
    顺序表和链表
    队列
    Redis系列教材 (二)- 运行
    Redis系列教材 (一)- windows教程
    Maven系列教材 (十三)- Eclipse 中创建父子-聚合项目
    Maven系列教材 (十一)- 使用Eclipse导入一个Maven风格的SSM项目
    Maven系列教材 (十)- 使用Eclipse创建一个Maven风格的SSM项目
    Maven系列教材 (九)- 在Eclipse中创建maven风格的java web项目
    Maven系列教材 (八)- 用命令行创建Maven风格的java web项目
  • 原文地址:https://www.cnblogs.com/__tudou__/p/12957199.html
Copyright © 2011-2022 走看看