本篇是学习Qt Creator快速入门,插件开发的笔记
分为两部分
-
创建插件
-
使用插件的应用程序(测试插件)
插件是被使用的应用程序加载使用的。 是使用插件的应用程序定义接口,插件按照接口来实现。
有几个需要注意的宏,其他的都是常规的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
完!
欢迎交流学习,共同进步
限本人水平有限,如有错误请指教,谢谢