在Visual Studio使用Qt的插件机制进行开发 - 指南

news/2025/11/9 19:09:56/文章来源:https://www.cnblogs.com/ljbguanli/p/19204713

在Visual Studio使用Qt的插件机制进行开发 - 指南

文章目录

    • Qt插件开发流程
    • Qt插件调用流程
    • 在Vs中开发Qt插件开发实例
      • 创建GUI应用工程PluginsTest
      • 创建插件子工程MyPlugin
      • 插件实现
        • 1. 定义一个接口
        • 2. 实现接口
        • 3. GUI应用的实现

参考链接:Qt Plugin插件开发之一:插件机制与实例

Qt插件开发流程

  1. 定义一个接口集(只有纯虚函数的类)。
  2. 用宏Q_DECLARE_INTERFACE()将该接口告诉Qt元对象系统
  3. 声明插件类,插件类继承自QObject和插件实现的接口。
  4. 用宏Q_INTERFACES()将插件接口告诉 Qt元对象系统(在头文件中)。

Qt插件调用流程

  1. 包含接口头文件(只有纯虚函数的类)。
  2. 应用程序中用QPluginLoader来加载插件。
  3. 用宏qobject_cast()来判断一个插件是否实现了接口。

在Vs中开发Qt插件开发实例

创建GUI应用工程PluginsTest

在确保安装有Qt VS Tools并能正常工作后,创建一个Qt Widgets应用程序。

在这里插入图片描述

创建插件子工程MyPlugin

一个Vs解决方案可以拥有多个工程。Qt的插件和动态库很像,都提供了动态加载的功能,它其实就是生成一个动态库供开发者使用。在解决方法(而不是在刚刚的创建的GUI工程)鼠标右键-->add-->new project->Qt Class Library
在这里插入图片描述

在这里插入图片描述

创建完插件子工程后,鼠标右键->属性->常规,我们可以看到Vs默认为我们将MyPlugin子工程的类型设置成了动态库类型。该工程默认会将动态库生成到$(SolutionDir)$(Platform)\$(Configuration)路径下,其中$(SolutionDir)代表解决解决方案的路径,$(Platform)代表当前电脑是x86还是x64架构,$(Configuration)表示解决方案是debug还是release。若想要指定动态库的生成路径,将该值替换成自己所需要的即可。我们需要记住动态库的生成路径,因为在GUI主工程中我们需要加载此动态库来加载Qt的插件。
在这里插入图片描述

由于GUI工程PluginsTest需要调用插件工程MyPlugin产生的动态库,所以需要把MyPlugin添加为PluginTest的依赖工程。在PluginTest上鼠标右键->构建依赖->工程依赖->选择MyPlugin
在这里插入图片描述

插件实现

1. 定义一个接口

PluginTest应用中增加一个接口Echonterface用于调用插件提供的方法,此接口定义在EchoInterface.h文件中。

#pragma once
#include <QString>#include <QtPlugin>// 1.定义一个接口集(只有纯虚函数的类)class EchoInterface{public:virtual ~EchoInterface() {}virtual QString echo(const QString& message) = 0;};// 2.用宏Q_DECLARE_INTERFACE()将该接口告诉Qt元对象系统QT_BEGIN_NAMESPACE#define EchoInterface_iid "org.qt-project.Qt.Examples.EchoInterface"Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid)QT_END_NAMESPACE
2. 实现接口

在插件子工程中添加一个插件类EchoPlugin,该类继承自QObject和上面讲到的插件接口EchoInterface
EchoPlugin.h文件内容:

#pragma once
#include <QObject>#include <QtPlugin>#include "../EchoInterface.h"	//在GUI主工程中定义的插件接口// 3.声明插件类,插件类继承自QObject和插件实现的接口class EchoPlugin  : public QObject, EchoInterface{// 3.用宏Q_INTERFACES()将插件接口告诉Qt元对象系统(在头文件中)Q_OBJECTQ_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.EchoInterface") // 宏需要声明通过对象实现的接口的IID,并引用一个包含插件元数据的文件Q_INTERFACES(EchoInterface)public:QString echo(const QString& message) override; // 实现的接口:返回字符串消息};

EchoPlugin.cpp 文件:

#include "EchoPlugin.h"
// 实现的接口:返回字符串消息
QString EchoPlugin::echo(const QString& message)
{
return message;
}

运行代码后,MyPlugin插件子工程会将动态库生成到$(SolutionDir)$(Platform)\$(Configuration)\中:
在这里插入图片描述
然后我们再在GUI主工程中加载就可以使用了。

3. GUI应用的实现

PluginsTest.h文件:

#include <QApplication>#include <QWidget>#include <QLabel>#include <QLineEdit>#include <QPushButton>#include <QGridLayout>#include <QMessageBox>#include <QDir>#include <QPluginLoader>#include "EchoInterface.h"class Widget : public QWidget{Q_OBJECTpublic:Widget();private slots:void sendEcho();private:void initUI(); // 初始化UIbool loadPlugin(); // 加载插件EchoInterface *m_pEchoInterface;QLineEdit *m_pLineEdit;QLabel *m_pLabel;QPushButton *m_pBtn;};

PluginsTest.cpp文件:

#include "PluginsTest.h"
PluginsTest::PluginsTest(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
// 初始化UI
initUI();
// 加载插件
if (!loadPlugin()) {
QMessageBox::information(this, "Error", "Could not load the plugin");
m_pLineEdit->setEnabled(false);
m_pBtn->setEnabled(false);
}
}
PluginsTest::~PluginsTest()
{}
void PluginsTest::sendEcho()
{
// 调用插件接口 - EchoPlugin::echo
QString text = m_pEchoInterface->echo(m_pLineEdit->text());
m_pLabel->setText(text);
}
// 初始化UI
void PluginsTest::initUI()
{
m_pLineEdit = new QLineEdit;
m_pLabel = new QLabel;
m_pLabel->setFrameStyle(QFrame::Box | QFrame::Plain);
m_pBtn = new QPushButton(tr("Send Message"));
connect(m_pLineEdit, &QLineEdit::editingFinished,
this, &PluginsTest::sendEcho);
connect(m_pBtn, &QPushButton::clicked,
this, &PluginsTest::sendEcho);
QGridLayout* m_pLayoutMain = new QGridLayout(this);
m_pLayoutMain->addWidget(new QLabel(tr("Message:")), 0, 0);
m_pLayoutMain->addWidget(m_pLineEdit, 0, 1);
m_pLayoutMain->addWidget(new QLabel(tr("Answer:")), 1, 0);
m_pLayoutMain->addWidget(m_pLabel, 1, 1);
m_pLayoutMain->addWidget(m_pBtn, 2, 1, Qt::AlignRight);
m_pLayoutMain->setSizeConstraint(QLayout::SetFixedSize);
}
// 加载插件
bool PluginsTest::loadPlugin()
{
bool ret = true;
// 获取当前应用程序所在路径
QDir pluginsDir(QDir::currentPath());
#if QT_POINTER_SIZE == 4
pluginsdir.cd("x32");
#elif QT_POINTER_SIZE == 8
pluginsDir.cd("x64");
#endif
#ifdef QT_DEBUG
pluginsDir.cd("debug");
#else
pluginsdir.cd("release");
#endif
qDebug() << pluginsDir.currentPath();
// 遍历plugins目录下所有文件
foreach(QString fileName, pluginsDir.entryList(QDir::Files)){
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject* plugin = pluginLoader.instance();
if (plugin){
// 获取插件名称
QString pluginName = plugin->metaObject()->className();
if (pluginName == "EchoPlugin"){
// 对插件初始化
m_pEchoInterface = qobject_cast<EchoInterface*>(plugin);if (m_pEchoInterface)ret = true;break;}else	ret = false;}}return ret;}

运行结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/960663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

摸鱼笔记[2]-提取windows已安装的驱动

使用`DriverStoreExplorer`提取windows已安装的海康相机.inf驱动文件.摘要 使用DriverStoreExplorer提取windows已安装的海康相机.inf驱动文件. 实现 [https://github.com/lostindark/DriverStoreExplorer] Driver Sto…

CF2013D 题解

提供一个二分做法。 因为当 \(a_i > a_{i + 1}\) 是做操作是不劣的,所以最终 \(a\) 一定单调不降。那么我们二分一个最小的 \(\max(a_i)\) 和最大的 \(\min(a_i)\),答案就是 \(\max(a_i) - \min(a_i)\)。 下面说一…

题解:AT_agc068_a [AGC068A] Circular Distance

牛牛题,看了很多次才看懂 题意:给出 \(L,n\),问在一个 \(L\) 长的环上,放置 \(n\) 个点,定义两点距离为两种路径中长度较短的长度,问所有放置方式的点的距离最大值之和。 做法: 首先先强制选定 \(0\) 号点,最后…

P14461 题解

消一消元: \[\begin{aligned}F_i&= G_{i - 1} + G_{i - 1} \\&= F_{i - 2} - F_{i - 2} + F_{i - 2} - F_{i - 2} \\&= F_{i - 2} - F_{i - 2} \end{aligned} \]类似的: \[G_i = G_{i - 2} - G_{i - 2} …

Nim 游戏与 SG 函数

已完成今日《Nim 游戏与 SG 函数》大学习。 本文比较基础,并未涉及到各种各样的 Nim 游戏,因为笔者比较菜。 1. 公平组合游戏 定义一个游戏为公平组合游戏,当且仅当:双方都知道当前局面的所有信息。 每一步的操作与…

题解:Luogu P11114 [ROI 2024] 小推车 (Day 1)

题意 有一排编号为 \(1\sim n\) 的座位。有 \(k\) 种饮料,第 \(i\) 名乘客想要喝第 \(a_i\) 种饮料。小推车需要从 \(0\) 位置出发,最终走到 \(n+1\) 位置,按顺序给每名乘客分饮料。推车上有 \(m\) 个瓶子,每个瓶子…

摸鱼笔记[1]-windows设置双网卡优先级(跃点数)

windows系统通过设置跃点数以设置双网卡优先级, 实现工控局域网网卡和互联网网卡各司其职, 电脑同时访问局域网和互联网.摘要 windows系统通过设置跃点数以设置双网卡优先级, 实现工控局域网网卡和互联网网卡各司其职,…

NXP - 用MDK建立基于arm-none-eabi软件链的工程框架

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

用 OKHttp 和 Retrofit 打造稳如磐石的网络请求:连接池与重试机制的实战指南 - 教程

用 OKHttp 和 Retrofit 打造稳如磐石的网络请求:连接池与重试机制的实战指南 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…

数字孪生重构智慧园区:众趣科技何以成为 VR 园区领域标杆 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

电脑监控软件,后台监控,千里眼监控

电脑监控软件,后台监控,适合家庭电脑、员工电脑监控 支持异地远程访问,终身授权最低100R,可月付年付 不限设备数量,支持win7、10、11 1、电脑位置显示 2、桌面远程观看 3、桌面文件下载 4、完整记录按键输入 5、智…

【URP】Unity[后处理]运动模糊MotionBlur

Motion Blur 概念与作用 Motion Blur(运动模糊)是一种模拟真实相机在拍摄快速移动物体或自身移动时产生的模糊效果的后处理技术。它通过模糊图像中运动物体的轨迹,增强动态场景的真实感和【从UnityURP开始探索游戏渲…

go sync.pool 学习笔记

概述 sync.pool 对象池可以用来复用临时对象,减少内存压力,降低 GC 压力。 示例 基本用法 type Worker struct{} func (w *Worker) Name() string { return "worker" } func main() { workerPool :…

初识分布式训练

假设有N块GPU,模型有ψ个参数。 前提知识:每个参数对应一个梯度值,且SGD每个参数对应一个一阶动量,Adam每个参数对应一个一阶、一个二阶动量DP(data parallel) ​ 数据并行(单进程,多线程,只用一个cpu核),每…

电脑监控软件,后台监控,适合家庭电脑、员工电脑监控

电脑监控软件,后台监控,适合家庭电脑、员工电脑监控 支持异地远程访问,终身授权,可月付年付 不限设备数量,支持win7、10、11 1、电脑位置显示 2、桌面远程观看 3、桌面文件下载 4、完整记录按键输入 5、智能屏幕快…

题解:P10856 【MX-X2-T5】「Cfz Round 4」Xor-Forces

题解 首先,我们先考虑简单的情况,没有修改操作。 由题意得,一段区间颜色段个数可以转化为区间长度减去相邻同色个数,即区间 \([l,r]\) 的颜色段数为 \(r-l+1- \sum^r_{i=l+1}[a_i=a_{i-1}]\)。 考虑线段树,那么一…

python: Virtualenv的安装与应用

一,安装Virtualenv 以ubuntu为例: 安装pip # apt install python3-pip 安装virtualenv # apt install python3-virtualenv二,创建环境 $ virtualenv -p /usr/bin/python3.12 myenv 三,进入/退出 环境 进入 $ sourc…