Qt 编写插件plugin,支持接口定义信号

https://blog.csdn.net/u014213012/article/details/122434193?spm=1001.2014.3001.5506
本教程基于该链接的内容进行升级,在编写插件的基础上,支持接口类定义信号。

环境:Qt5.12.12 + MSVC2017

一、创建项目

  1. 新建一个子项目便于程序管理【文件->新建文件或项目->其它项目->子目录项目】
    在这里插入图片描述
    2.本次演示项目命名为【PluginProject】,然后指定目录
    在这里插入图片描述

3.指定构建套件
在这里插入图片描述

4.完成并添加应用程序项目
在这里插入图片描述

二、创建调试项目

1.做好上一个步骤后,会自动弹窗新建子项目【Application->Qt Widgets Application】
在这里插入图片描述

2.本次演示应用程序命名为【MainApp】默认mainwindow窗口类
在这里插入图片描述

在这里插入图片描述

3.创建完成的项目结构如下
在这里插入图片描述
4.【项目->关掉shadow build】免得后面找不到插件路径
在这里插入图片描述

三、创建插件项目

1.【PluginProject->右键->新子项目->Application->Qt Widgets Application】
在这里插入图片描述
在这里插入图片描述

  1. 项目名为【PluginApp】
    在这里插入图片描述

3.基类选择QWidget,基类改名为【PluginWidget】
在这里插入图片描述

4.完成后的项目结构
在这里插入图片描述

5.在PluginApp.pro中添加以下配置:

TARGET = PluginApp
TEMPLATE =lib                        #template改app为lib
CONFIG += plugin                     #增加plugin的配置
DESTDIR = ../MainApp/debug/plugin    #目标直接生成到MainApp的debug/plugin 

在这里插入图片描述

6.【PluginApp->右键->新增C++ Header File】命名为abstractinterface
在这里插入图片描述

在这里插入图片描述

7.abstractinterface是对外暴漏的接口类
类里的函数必须是纯虚的,使用Q_DECLARE_INTERFACE()宏向Qt的元对象系统声明该接口
为了能在接口暴漏信号,必须使用Q_OBJECT宏,因此该类需要继承QObject

#ifndef ABSTRACTINTERFACE_H
#define ABSTRACTINTERFACE_H#include <QtPlugin>
class QWidget;
class AbstractInterface:public QObject{Q_OBJECT
public:virtual ~AbstractInterface(){}  //必须定义虚析构函数virtual QWidget* createWidgetPlugin(QWidget *parent)  = 0;
signals:virtual void printMessage(QString text)  = 0;
};
#define AbstarctInterface_IID "qt.org.com.abstactinterface/1.0"   //iid随便命名当前项目独一无二即可
Q_DECLARE_INTERFACE(AbstractInterface,AbstarctInterface_IID)      //声明接口#endif // ABSTRACTINTERFACE_H

在这里插入图片描述

8.【PluginApp->右键->新增C++ Class】命名为InterfaceImplement
在这里插入图片描述

在这里插入图片描述

9.InterfaceImplement是接口实现类,继承AbstractInterface。
使用Q_INTERFACES()宏告诉Qt的元对象系统有关接口的信息
使用Q_PLUGIN_METADATA ()宏导出插件。

#ifndef INTERFACEIMPLEMENT_H
#define INTERFACEIMPLEMENT_H#include"abstractinterface.h"class InterfaceImplement:public AbstractInterface
{
public:Q_OBJECTQ_INTERFACES(AbstractInterface)                              //实现的接口Q_PLUGIN_METADATA(IID AbstarctInterface_IID)                 //导出接口后面的 FILE “jsonfile”可省略
public:explicit InterfaceImplement();~InterfaceImplement() override;QWidget *createWidgetPlugin(QWidget *parent) override;
signals:void printMessage(QString text)  override;
};
#endif // INTERFACEIMPLEMENT_H

在这里插入图片描述

10.双击PluginWidget.ui,拖个按钮
在这里插入图片描述
14.右键PushButton->转到槽->选择clicked()->OK
在这里插入图片描述
15. PluginWidget.h添加:

signals:void sendMessage(QString text);

在这里插入图片描述

  1. PluginWidget.cpp的on_pushButton_clicked槽函数内,发射”hello world字符:
emit sendMessage("hello world");

在这里插入图片描述

17.在InterfaceImplement.cpp实现createWidgetPlugin,返回PluginWidget的实例,转发信号

#include "interfaceimplement.h"
#include "pluginwidget.h"
InterfaceImplement::InterfaceImplement()
{}InterfaceImplement::~InterfaceImplement()
{}QWidget *InterfaceImplement::createWidgetPlugin(QWidget *parent) 
{PluginWidget * w = new PluginWidget(parent);     //返回PluginApp实现的界面类connect(w, &PluginWidget::sendMessage, this, [this](const QString &text) {emit printMessage(text);});return w;
}

在这里插入图片描述

四.调试插件

1.MainApp.pro添加抽象类所在的目录:

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11
INCLUDEPATH += ../PluginApp            #包含PluginApp创建的HandEyePositionInterface.hSOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.ui

在这里插入图片描述
2.右键MainApp->执行qmake
在这里插入图片描述

3.点开MainApp下的mainwindow.h,使用QPluginLoader加载插件.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
class AbstractInterface;QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();
private slots:void print(QString text);
private:Ui::MainWindow *ui;
private:void loadPlugin();              //应用程序装载插件
private:AbstractInterface *mainInterface;      //插件类
};
#endif // MAINWINDOW_H

在这里插入图片描述

4.在loadPlugin()中加载插件。注意连接插件信号的connect要用SIGNAL() SLOT()的方式连

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "abstractinterface.h"
#include <QDir>
#include <QPluginLoader>     //包含插件装载头文件
#include <QVBoxLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);loadPlugin();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::print(QString text)
{qDebug() << "Received message from plugin:" << text;
}void MainWindow::loadPlugin()
{//插件存放在应用程序目录下的plugin目录下,便于管理QDir pluginDir(qApp->applicationDirPath());  //定位应用程序目录if( pluginDir.cd("plugin") )                 //进入plugin,前提先创建plugin目录{for(auto fileName:pluginDir.entryList(QDir::Files))  //遍历目录下的文件{QFileInfo info(fileName);if(info.completeSuffix() == "dll" || info.completeSuffix() == "so")  //过滤后缀为dll或so的动态库文件{QPluginLoader load(pluginDir.absoluteFilePath(fileName));        //装载插件QObject *pluginObj = load.instance();                            //获取插件根对象if(pluginObj){mainInterface = qobject_cast<AbstractInterface *>(pluginObj);  //转换QWidget*w =mainInterface->createWidgetPlugin(this);connect(mainInterface, SIGNAL(printMessage(QString)), this, SLOT(print(QString)));//注意,使用字符串连接的方式,避免编译阶段进行类型检查if (!ui->centralwidget->layout()){ui->centralwidget->setLayout(new QVBoxLayout());}ui->centralwidget->layout()->addWidget(w);  // 将插件小部件添加到 centralwidget 的布局中}}}}}

5.运行后点按钮,看输出效果
在这里插入图片描述

五.其他说明

如果插件类和实现类用到了三方库,以本项目为例,PluginApp.pro添加了三方库3rdParty.pri。那么在调试类,也需要包含同样的三方库,也就是本项目的MainApp.pro也需要包含这个3rdParty.pri,才能正常使用。

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

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

相关文章

Qt 监控USB设备的插入和移除

Qt 监控USB设备的插入和移除 flyfish Ubuntu22.04 Qt 6.2.4 CMakeLists.txt 内容 # 指定 CMake 的最低版本要求 cmake_minimum_required(VERSION 3.16)# 定义项目的名称和使用的编程语言 project(USBMonitor LANGUAGES CXX)# 开启自动 UIC&#xff0c;MOC 和 RCC 工具 set(…

MFC工控项目实例二十九主对话框调用子对话框设定参数值

在主对话框调用子对话框设定参数值&#xff0c;使用theApp变量实现。 子对话框各参数变量 CString m_strTypeName; CString m_strBrand; CString m_strRemark; double m_edit_min; double m_edit_max; double m_edit_time2; double …

《C++在金融领域的技术革命:高效、安全与创新的融合》

引言 在当今数字化高速发展的时代&#xff0c;金融领域对技术的需求日益增长。C作为一种强大的编程语言&#xff0c;以其高效的执行性能、强大的内存管理能力和丰富的功能库&#xff0c;在金融领域中占据着重要的地位。本文将深入探讨 C在金融领域的热点技术应用&#xff0c;以…

mac上使用docker搭建gitlab

在 Mac 上搭建 GitLab 可以使用 Docker 来简化安装过程 一、安装详细步骤 1. 安装 Docker 如果你尚未安装 Docker&#xff0c;可以通过以下步骤安装&#xff1a; 下载并安装 Docker Desktop for Mac.安装完成后&#xff0c;启动 Docker Desktop&#xff0c;确保 Docker 运行…

x-cmd pkg | lf - 轻量级终端文件管理器,开销低,效率高,适合资源受限的环境

目录 简介快速上手安装使用 技术特点竞品和相关项目进一步阅读 简介 lf&#xff08;list files&#xff09;是 github.com/gokcehan 用 Go 开发的轻量级终端文件管理器&#xff0c;能提供一个通过键盘快捷键进行文件浏览、操作和管理的方法。它的界面风格和操作模式类似于 ran…

D64【python 接口自动化学习】- python基础之数据库

day64 SQL-DQL-基础查询 学习日期&#xff1a;20241110 学习目标&#xff1a;MySQL数据库-- 133 SQL-DQL-基础查询 学习笔记&#xff1a; 基础数据查询 基础数据查询-过滤 总结 基础查询的语法&#xff1a;select 字段列表|* from 表过滤查询的语法&#xff1a;select 字段…

力士乐工控机触摸屏面板维修CFG-BTV40.BN

力士乐工控机触摸屏维修包括BTV20系列&#xff0c;BTV30系列&#xff0c;BTV40等系列均可提供维修服务。 力士乐工控机维修&#xff0c;先区分故障是来自小信号处理部分&#xff0c;还是功率部分故障&#xff0c;很多设备的上位机会有所提示。处理部分包括i/o端口&#xff0c;…

数据挖掘全景:从基础理论到经典算法的深度探索

1 绪论--1.1 数据挖掘的概念和任务 1. (单选题)目前数据分析与挖掘领域的现实情况描述不正确的是&#xff08;&#xff09; A. 信息爆炸 B. 数据爆炸 C. 信息贫瘠 D.数据收集能力远远超过人们的分析和理解能力 2. (单选题)你认为下面哪种数据对于数据挖掘算法来说最简单最…

简易入手《SOM神经网络》的本质与原理

原创文章&#xff0c;转载请说明来自《老饼讲解神经网络》:www.bbbdata.com 关于《老饼讲解神经网络》&#xff1a; 本网结构化讲解神经网络的知识&#xff0c;原理和代码。 重现matlab神经网络工具箱的算法&#xff0c;是学习神经网络的好助手。 目录 一、入门原理解说 01.…

ubuntu 安装kafka-eagle

上传压缩包 kafka-eagle-bin-2.0.8.tar.gz 到集群 /root/efak 目录 cd /root/efak tar -zxvf kafka-eagle-bin-2.0.8.tar.gz cd /root/efak/kafka-eagle-bin-2.0.8 mkdir /root/efakmodule tar -zxvf efak-web-2.0.8-bin.tar.gz -C /root/efakmodule/ mv /root/efakmodule/efak…

小程序服务商常见问题

1: 服务器域名和开发域名都不带https前缀, 业务域名每个都需要校验文件 2: 手机开了调试可以请求, 关闭调试无法请求, 体验版接口请求不同 答: 服务商还需要通过接口给小程序设置业务域名; 但不需要校验文件; 注意: 体验版通过快速配置小程序服务器域名接口会不生效, 用普通的 …

Llama架构及代码详解

Llama的框架图如图&#xff1a; 源码中含有大量分布式训练相关的代码&#xff0c;读起来比较晦涩难懂&#xff0c;所以我们对llama自顶向下进行了解析及复现&#xff0c;我们对其划分成三层&#xff0c;分别是顶层、中层、和底层&#xff0c;如下&#xff1a; Llama的整体组成…

Docker在微服务架构中的最佳实践

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Docker在微服务架构中的最佳实践 Docker在微服务架构中的最佳实践 Docker在微服务架构中的最佳实践 引言 Docker 概述 定义与原理…

排序算法 - 冒泡

文章目录 1. 冒泡排序1.1 简介1.2 基本步骤&#xff1a;1.3 示例代码&#xff08;C&#xff09;1.4 复杂度分析1.5 动画展示 1. 冒泡排序 1.1 简介 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;其基本思想是通过相邻元素的比较和交换&#…

Spring MVC 与 JSP 数据传输

在Spring MVC框架中&#xff0c;控制器&#xff08;Controller&#xff09;与视图&#xff08;View&#xff09;之间的数据传输是一个常见的操作。本文将介绍几种在Spring MVC中将数据从控制器传递到JSP页面的方法&#xff0c;并提供相应的代码案例。 1. 使用Model对象 Sprin…

理解 HTML5 Canvas 中逻辑像素与物理像素的关系

理解 HTML5 Canvas 中逻辑像素与物理像素的关系 在使用 HTML5 Canvas 时&#xff0c;开发者经常会遇到一个困惑&#xff1a;为什么鼠标的 offsetX 和 offsetY 和我绘制的图形坐标对不上&#xff1f;这通常是因为 Canvas 的逻辑像素大小和物理像素大小不一致。本文将详细解释这…

Nginx在Windows上和Linux上(Docker启动)分别配置基本身份认证示例

场景 Nginx代理的资源或网站等&#xff0c;url直接暴露有风险&#xff0c;需要添加身份认证&#xff0c;即输入用户名密码后才能成功访问。 注&#xff1a; 博客&#xff1a;霸道流氓气质-CSDN博客 实现 Windows上配置Nginx实现基本身份认证 修改nginx的配置文件 添加基…

丹摩征文活动|丹摩智算平台使用指南

目录 1. 登录平台与工作环境设置1.1 访问与登录1.2 创建或选择项目1.3 初始化项目环境 2. 数据上传与管理2.1 数据上传2.2 数据管理与预处理2.3 数据可视化 3. 模型构建与训练3.1 模型选择3.2 参数配置3.3 模型训练与评估 4. 模型部署与应用4.1 模型部署4.2 接口调用与集成4.3 …

用MVVM设计模式提升WPF开发体验:分层架构与绑定实例解析

MVVM&#xff08;Model-View-ViewModel&#xff09;是一种架构模式&#xff0c;广泛应用于现代前端开发&#xff0c;尤其是在微软的WPF&#xff08;Windows Presentation Foundation&#xff09;应用程序中。它旨在通过将视图&#xff08;UI&#xff09;与业务逻辑&#xff08;…

std::memory_order 多线程编程中的内存顺序

std::memory_order 是 C11 引入的一个枚举&#xff0c;用于控制多线程编程中的内存顺序。它定义了在原子操作中对内存的可见性和排序的要求。它在 C 标准库的 <atomic> 头文件中&#xff0c;配合原子类型和操作&#xff08;如 std::atomic 和 std::atomic_flag&#xff0…