qt 从零开始搭建插件框架

系统设计

搭建插件框架的好处

分析

至少分为以下几个模块

  1. 需要至少一个界面插件,用于展示界面
  2. 需要一些功能插件,为界面提供所需功能,例如FTP功能,网络服务,数据库等等
  3. 需要一个插件用于管理其他插件,插件间的通信,维护等等
  4. 需要一个启动程序作为入口

流程

  1. mainApp项目作为启动整个程序的入口,生成传统意义上的exe文件,点击它启动软件
  2. 启动之后,需要加载管理插件的插件项目(命名为QtPluginFramework)
  3. QtPluginFramework加载各个插件:包括界面插件,功能插件等等
  4. 界面显示,用户互动产生命令调用功能插件
  5. 用户退出界面,QtPluginFramework卸载各个插件
  6. mainApp退出

QtPluginFramework项目

分析

插件式开发的好处在于,每个人可以独立的负责某个小的模块,这个模块还可以给其他的项目组用,而且很方便添加其他功能。所以QtPluginFramework项目的作用就是

  1. 定义一个公共接口QtPluginInterface,所有的插件都必须实现这个接口
  2. 加载和卸载单个插件的功能,定义QtPlugin类
  3. 集中管理所有插件的功能,定义QtPluginManage类
  4. 插件间的通信功能,定义QtEvents类
  5. 最后定义QtPluginFramework类,集成以上所有功能

实现

QtPluginInterface
#ifndef QtPluginInterface_H_
#define QtPluginInterface_H_

class CPluginFramework;
class QtPluginInterface
{
public:
	virtual ~QtPluginInterface(){}
	//
	virtual void Start(QtPluginFramework* pPluginFramework) = 0;
	//
	virtual void Stop(QtPluginFramework* pPluginFramework) = 0;
};

Q_DECLARE_INTERFACE(QtPluginInterface, "Plugin.QtPluginInterface")

#endif 
QtPlugin

加载和卸载单个插件

在这里插入代码片

参考文献

参考文献1
参考 qt 官方示例 Echo Plugin Example
怎样用 Qt 写个插件?
在项目中创建并使用自定义Qt插件【VS+Qt项目开发系列】(六)
使用ctkPluginFramework插件系统构建项目实战 **
ctk github
CTK框架使用简明教程
QT——插件的创建和使用

实战

新建库项目

在这里插入图片描述
选择chose进入下一下页面,类型选择Qt Plugin,输入一个名称

新建如下文件
在这里插入图片描述

首先需要一个虚接口 echointerface.h,在插件工程和要运行插件的工程中都要使用

#ifndef ECHOINTERFACE_H
#define ECHOINTERFACE_H

#include <QObject>
#include <QString>

//! [0]
class EchoInterface
{
public:
    virtual ~EchoInterface() = default;
    virtual QString echo(const QString &message) = 0;
};


QT_BEGIN_NAMESPACE

#define EchoInterface_iid "org.qt-project.Qt.Examples.EchoInterface"

Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid)
QT_END_NAMESPACE

//! [0]
#endif

Q_DECLARE_INTERFACE() 向 Qt 元对象系统注册一下我写的这个接口。
该宏的第一个参数是接口类的名字,第二个参数是 iid(相当于一个身份证信息,可以随便写个字符串)。

至此,我的程序给外界提供了个公共接口,并且为了 Qt 编程方便还向元对象系统注册了一下。以后所有的插件都通过这个接口来扩展 app 的功能,当然也可以写更多的接口供外界调用。

接下来是写插件,要继承这个接口
echoplugin.h


#ifndef ECHOPLUGIN_H
#define ECHOPLUGIN_H

#include <QObject>
#include <QtPlugin>
#include "echointerface.h"

//! [0]
class EchoPlugin : public QObject, EchoInterface
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.EchoInterface" FILE "MyQtPlugin.json")
    Q_INTERFACES(EchoInterface)

public:
    QString echo(const QString &message) override;
};
//! [0]

#endif

echoplugin.cpp

#include "echoplugin.h"

//! [0]
QString EchoPlugin::echo(const QString &message)
{
    return message;
}
//! [0]

然后编译生成,我们需要
MyQtPlugin.dll MyQtPlugin.lib echointerface.h这三个文件

我们再新建一个工程 做一个界面
在这里插入图片描述
把刚才那三个文件复制到现在工程的目录下,把echointerface.h添加到工程里面(右键添加现有文件)
在这里插入图片描述
echowindow.h

#ifndef ECHOWINDOW_H
#define ECHOWINDOW_H

#include <QWidget>
#include "echointerface.h"

QT_BEGIN_NAMESPACE
class QString;
class QLineEdit;
class QLabel;
class QPushButton;
class QGridLayout;
namespace Ui { class echowindow; }
QT_END_NAMESPACE

class echowindow : public QWidget
{
    Q_OBJECT

public:
    echowindow();
    ~echowindow();

private slots:
    void sendEcho();

private:
    void createGUI();
    bool loadPlugin();

    EchoInterface *echoInterface;
    QLineEdit *lineEdit;
    QLabel *label;
    QPushButton *button;
    QGridLayout *layout;
};
#endif // ECHOWINDOW_H

echowindow.cpp

#include "echowindow.h"
#include "ui_echowindow.h"
#include "echowindow.h"

#include <QCoreApplication>
#include <QDir>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QMessageBox>
#include <QPluginLoader>
#include <QPushButton>

//! [0]
echowindow::echowindow()
{
    createGUI();
    setLayout(layout);
    setWindowTitle("Echo Plugin Example");

    if (!loadPlugin()) {
        QMessageBox::information(this, "Error", "Could not load the plugin");
        lineEdit->setEnabled(false);
        button->setEnabled(false);
    }
}
//! [0]

//! [1]
void echowindow::sendEcho()
{
    QString text = echoInterface->echo(lineEdit->text());
    label->setText(text);
}
//! [1]

//! [2]
void echowindow::createGUI()
{
    lineEdit = new QLineEdit;
    label = new QLabel;
    label->setFrameStyle(QFrame::Box | QFrame::Plain);
    button = new QPushButton(tr("Send Message"));

    connect(lineEdit, &QLineEdit::editingFinished,
            this, &echowindow::sendEcho);
    connect(button, &QPushButton::clicked,
            this, &echowindow::sendEcho);

    layout = new QGridLayout;
    layout->addWidget(new QLabel(tr("Message:")), 0, 0);
    layout->addWidget(lineEdit, 0, 1);
    layout->addWidget(new QLabel(tr("Answer:")), 1, 0);
    layout->addWidget(label, 1, 1);
    layout->addWidget(button, 2, 1, Qt::AlignRight);
    layout->setSizeConstraint(QLayout::SetFixedSize);
}
//! [2]

//! [3]
bool echowindow::loadPlugin()
{
    QDir pluginsDir(QCoreApplication::applicationDirPath());
#if defined(Q_OS_WIN)
    if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
        pluginsDir.cdUp();
#elif defined(Q_OS_MAC)
    if (pluginsDir.dirName() == "MacOS") {
        pluginsDir.cdUp();
        pluginsDir.cdUp();
        pluginsDir.cdUp();
    }
#endif
    pluginsDir.cd("plugins");
    const QStringList entries = pluginsDir.entryList(QDir::Files);
    for (const QString &fileName : entries) {
        QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
        QObject *plugin = pluginLoader.instance();
        if (plugin) {
            echoInterface = qobject_cast<EchoInterface *>(plugin);
            if (echoInterface)
                return true;
            pluginLoader.unload();
        }
    }

    return false;
}

echowindow::~echowindow()
{

}


main.cpp

#include "echowindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    echowindow w;
    w.show();
    return a.exec();
}

  • 5
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt 插件框架是一种动态加载的机制,它允许在运行时向 Qt 应用程序中添加功能模块。Qt 插件框架的实现原理主要包括以下几个方面: 1. 插件分类 Qt 插件框架插件分为两类:静态插件和动态插件。静态插件是编译到应用程序中的插件,它们在应用程序启动时被加载。动态插件是独立于应用程序的库,它们在运行时被加载。 2. 插件接口 Qt 插件框架定义了插件接口,插件必须实现这些接口才能被加载。插件接口通常是一个纯虚类,它们定义了插件的功能、属性和行为。 3. 插件元数据 Qt 插件框架使用元数据来描述插件,包括插件名、版本号、作者、描述、依赖关系等信息。插件元数据通常以 XML 格式存储。 4. 插件加载 Qt 插件框架使用 QPluginLoader 类来加载插件。QPluginLoader 会根据插件的元数据查找插件库,并调用插件接口的实现来完成插件的加载和初始。 5. 插件管理 Qt 插件框架提供了插件管理器来管理插件插件管理器可以枚举、查找、加载和卸载插件,还可以管理插件间的依赖关系。 6. 插件通信 Qt 插件框架提供了信号和槽机制来实现插件之间的通信。插件可以通过信号和槽来传递消息和数据,实现插件之间的互操作。 总之,Qt 插件框架提供了一种灵活、可扩展的机制,使得应用程序可以在运行时加载和卸载插件,从而实现更丰富、更灵活的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值