怎样创建Qt应用程序插件
Qt给我们提供了一种方便使用的应用程序插件技术,让我们在开发软件时能够更加的灵活。那么怎样创建插件呢?有哪些需要注意的地方呢?具体的步骤是怎样的呢?本文基于Qt Assistant中的Echo plugin Example例子进行了梳理和总结。
工具/原料
一台安装有Qt集成开发环境的windows或linux
一、创建一个基于QWidget的窗体程序
1、演示示例创建的是一个基于QWidget类的窗体程序,当然你要使用其他窗体类也是可以的。项目名称为EchoWindow,窗体类名采用的是默认的widget。项目位于明为MyPlugin的目录下。整个的目录结构如下:
2、具体程序界面如下。点击发送后,将文本框的内容经过插件的简单处理后在黑色框线的标签控件中显示出来。
二、建立接口类
1、首先了解下什么是接口。接口类就是,由纯虚函数构成的类。它是不能够被实例化的。在Assistant中有简短的说明。如果类中没有虚函数会被编译器报错的。
2、下面我们来建立接口类。在EchoWindow项目上右键,添加新文件。
3、在弹出的 新建文件 对话框中,我们选择C++,中间窗口选择 C++ Header File。然后点击choose。
4、输入名称 EchoInterface。当然,也可以是任何你喜欢的名字。点击下一步,然后点击完成。
5、我们来看看,EchoWindow项目的目录情况。
6、在EchoInterface.h中输入以下内容:#ifndef ECHOINTER掂迎豢畦FACE#define ECHOINTERFACE#include <QString>class EchoInterface{public: virtual ~EchoInterface() {} virtual QString echo(const QString &message) = 0;};#define EchoInterface_iid "Examples.Plugin.EchoInterface"Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid)#endif // ECHOINTERFACE
7、可以看到类中只有一个纯虚函数。Q_DECLARE_INTERFACE宏是为了让Qt的元对象系统知道这是一个接口。同时还要注意那个iid,我们的是"Examples.Plugin.EchoInterface",待会会用到。好的,到此,我们的接口类编写完毕。
三、创建插件项目
1、点击文件菜单,新建文件或项目。
2、在弹出的 New File or Project 窗口中,我们选择,其他项目,Empty qmake project,然后choose。
3、在弹出的Empty qmake project窗口中,名称我们输入Plugin,路径我们按照第一步第一个图来存放,也就是与EchoWindow在同级目录下即可。然后,一直下一步,直到完成。
4、我们再来看看当前的整个项目结构。Plugin确实是个空项目,什么都没有。
5、我们在Plugin项目上右键,选择添加新文件,这个与添加那个接口类是一样的。在弹出的 新建文件 窗口中,我们选择C++,中间选择C++ class。然后点击Choose。
6、在弹出的C++ class窗口中,我们按图中输入。然后下一步。再点击完成。
7、首先来编辑下p盟敢势袂lugin.pro文件。输入如下内容:TEMPLATE = libCONFIG += plug足毂忍珩inQT += widgetsINCLUDEPATH += ../echowindowHEADERS = echoplugin.hSOURCES = echoplugin.cppTARGET = $$qtLibraryTarget(echoplugin)DESTDIR = ../plugins然后保存。第一行:生成的是一个库文件。第二行:这是一个插件第四行:因为我们要用到刚才定义的接口类,而该类的位置在echowindow中。第七行:生成的库的名称,后缀名qt会根据系统自动添加。第八行:生成文件的存放位置。
8、在echoplugin.h中输入:#include <QObject>拭貉强跳#include <QtPlugin>#include "ech泠贾高框ointerface.h"class EchoPlugin : public QObject, EchoInterface{ Q_OBJECT Q_PLUGIN_METADATA(IID "Examples.Plugin.EchoInterface") Q_INTERFACES(EchoInterface)public: EchoPlugin(); QString echo(const QString &message) Q_DECL_OVERRIDE;};Q_INTERFACES告诉Qt类实现的是哪个接口,它的参数可以有多个。Q_PLUGIN_METADATA包含了我们刚才定义的IID。同时可以看到,我们的EchoPlugin继承自QObject和EchoInterface。并且下面也有一个echo函数,这是我们要具体实现的纯虚函数。
9、现在来实现echoplugin.cpp文件。很简单:#include "echoplugin.h"#include <QtWidgets>Echo霸烹钟爷Plugin::EchoPlugin(){}QString EchoPlugin::echo(const QString &message){ return QString("process:")+message;}echo函数只是在参数前面加上了process然后直接返回了。
四、编写窗体程序的代码
1、widget.h的代码如下:#ifndef WIDGET_H#define WIDGET_H#include <QWidget>稆糨孝汶;#include "echointerface.h"namespace Ui {class Widget;}class Widget : public QWidget{ Q_OBJECTpublic: explicit Widget(QWidget *parent = 0); ~Widget();private slots: void on_pushButton_send_clicked();private: Ui::Widget *ui; EchoInterface *echoInterface; bool loadPlugin();};#endif // WIDGET_H我们定义了一个接口类的指针。以及一个loadPlugin函数。
2、widget.cpp代码:#include "widget.h"#include "ui_widget.h"#include <QDir>#include <QMessageBox>#include <QtWidgets>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_origin_msg->setEnabled(false); ui->pushButton_send->setEnabled(false); }}Widget::~Widget(){ delete ui;}bool Widget::loadPlugin(){ QDir pluginsDir(qApp->applicationDirPath()); pluginsDir.cd("plugins"); foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName)); QObject *plugin = pluginLoader.instance(); if (plugin) { echoInterface = qobject_cast<EchoInterface *>(plugin); if (echoInterface) return true; } } return false;}void Widget::on_pushButton_send_clicked(){ QString ans=echoInterface->echo(ui->lineEdit_origin_msg->text()); ui->label_answer->setText(ans);}注意我们的载入插件函数,我们在窗口的初始化过程中调用了该函数。该函数找到插件文件后,通过QPluginLoader 对象进行载入,然后调用函数instance实例化类并返回一个QObject对象指针,然后通过一个静态强制转换为我们的接口类指针。然后我们点击按钮时,就可以使用该指针调用echo函数处理文本框的字符串,并返回处理后的字符串。之后,在标签控件中显示出来。
五、构建项目,运行程序
1、我们分别在两个项目上右键,选择 构建 菜单。
2、构建完毕后,可以看到,我们的插件生成了。我们的窗体程序也生成了。
3、将生成的插件拷贝到生成的窗体程序的目录。
4、可以运行程序了。因为我们生成的是debug程序,所以我们在IDE中运行它。右键将 EchoWindow设置为活跃项目。
5、然后点击运行,如果设为活跃后运行按钮时灰色,你可以先将项目套件设置为release,然后再换回来。来看看运行的情况。看来我们的插件起作用了。
6、至于为什么插件是放在plugins文件夹中,是因为我们在编写plugin插件时pro文件的设置,更重要的是我们的loadPlugin函数是在可执行文件同级目录下的plugins文件夹中寻找,这才是根本。当然你可以修改该函数代码,把插件放在任何你想放置的地方。好了,整个插件的编写过程到此结束。