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.rhkb.cn/news/469980.html

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

相关文章

PaaS云原生:分布式集群中如何构建自动化压测工具

场景 测试环境中&#xff0c;压测常常依赖环境中的各种工具获取基础信息&#xff0c;而这些工具可能集中在某个中控机上&#xff0c;此时想打造的自动化工具的运行模式是&#xff1a; 通过中控机工具获取压测所需的基本信息在中控机部署压测工具&#xff0c;实际压测任务分发…

关于sass在Vue3中编写bem框架报错以及警告问题记录

在编写完bem框架后 在vite.config.ts文件进行预编译处理时&#xff0c;报错的错误 1. 处理方式&#xff1a;使用新版api&#xff0c; 如图&#xff1a; 2. 处理方式&#xff1a;使用 use 替换掉 import&#xff0c; 如图&#xff1a; 3. 处理方式&#xff1a;使用路径别名&am…

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪

内置RTK北斗高精度定位的4G执法记录仪、国网供电服务器记录仪BD311R 发布时间: 2024-10-23 11:28:42 一、 产品图片&#xff1a; 二、 产品特性&#xff1a; 4G性能&#xff1a;支持2K超高清图传&#xff0c;数据传输不掉帧&#xff0c;更稳定。 独立北…

【前端】深入浅出的React.js详解

React 是一个用于构建用户界面的 JavaScript 库&#xff0c;由 Facebook 开发并维护。随着 React 的不断演进&#xff0c;官方文档也在不断更新和完善。本文将详细解读最新的 React 官方文档&#xff0c;涵盖核心概念、新特性、最佳实践等内容&#xff0c;帮助开发者更好地理解…

【Elasticsearch入门到落地】1、初识Elasticsearch

一、什么是Elasticsearch Elasticsearch&#xff08;简称ES&#xff09;是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容。它使用Java编写&#xff0c;基于Apache Lucene来构建索引和提供搜索功能&#xff0c;是一个分布式、可扩展、近实…

扫雷游戏代码分享(c基础)

hi , I am 36. 代码来之不易&#x1f44d;&#x1f44d;&#x1f44d; 创建两个.c 一个.h 1&#xff1a;test.c #include"game.h"void game() {//创建数组char mine[ROWS][COLS] { 0 };char show[ROWS][COLS] { 0 };char temp[ROWS][COLS] { 0 };//初始化数…

ORA-01092 ORA-14695 ORA-38301

文章目录 前言一、MAX_STRING_SIZE--12C 新特性扩展数据类型 varchar2(32767)二、恢复操作1.尝试恢复MAX_STRING_SIZE参数为默认值2.在upgrade模式下执行utl32k.sql 前言 今天客户发来一个内部测试库数据库启动截图报错&#xff0c;描述是“上午出现服务卡顿&#xff0c;然后重…

ODOO学习笔记(3):Odoo和Django的区别是什么?

Odoo和Django都是基于Python的开源框架&#xff0c;但它们的设计目标和用途有所不同&#xff1a; 设计目标和用途&#xff1a; Odoo&#xff1a;Odoo是一个企业资源规划&#xff08;ERP&#xff09;系统&#xff0c;它提供了一套完整的商业管理软件&#xff0c;包括会计、库存…

零基础玩转IPC之——海思平台实现P2P远程传输实验(基于TUTK,国科君正全志海思通用)

老规矩&#xff0c;先做实验测试。以本店Hi3516EV200\GK7205开发板为例&#xff0c;其他开发板操作类似。 将源码包p2p-h264.tgz放到虚拟机&#xff0c;解压&#xff0c;编译 tar -jxvf p2p-h264.tgz cd p2p-h264 make clean make 得到可执行文件p2p-h264 启动开发板&…

如何理解DDoS安全防护在企业安全防护中的作用

DDoS安全防护在安全防护中扮演着非常重要的角色。DDoS&#xff08;分布式拒绝服务&#xff09;攻击是一种常见的网络攻击&#xff0c;旨在通过向目标服务器发送大量请求&#xff0c;以消耗服务器资源并使其无法正常运行。理解DDoS安全防护的作用&#xff0c;可以从以下几个方面…

Python如何从HTML提取img标签下的src属性

目录 前提准备步骤1. 解析HTML内容2. 查找所有的img标签3. 提取src属性 完整代码 前提准备 在处理网页数据时&#xff0c;我们经常需要从HTML中提取特定的信息&#xff0c;比如图片的URL。 这通常通过获取img标签的src属性来实现。 在开始之前&#xff0c;你需要确保已经安装…

Redis主从复制(replication)

文章目录 是什么作用使用案例实操主从复制原理和工作流程slave启动&#xff0c;同步初请首次连接&#xff0c;全量复制心跳持续&#xff0c;保持通信进入平稳&#xff0c;增量复制从机下线&#xff0c;重连续传 复制的缺点 是什么 主从复制&#xff0c;master以写为主&#xf…

Android OpenGL ES详解——纹理:纹理过滤GL_NEAREST和GL_LINEAR的区别

目录 一、概念 1、纹理过滤 2、邻近过滤 3、线性过滤 二、邻近过滤和线性过滤的区别 三、源码下载 一、概念 1、纹理过滤 当纹理被应用到三维物体上时&#xff0c;随着物体表面的形状和相机视角的变化&#xff0c;会导致纹理在渲染过程中出现一些问题&#xff0c;如锯齿…

记录日志中logback和log4j2不能共存的问题

本文章记录设置两个日志时候&#xff0c;控制台直接报错 标黄处就是错误原因&#xff1a;1. SLF4J(W)&#xff1a;类路径包含多个SLF4J提供程序。 SLF4J(W)&#xff1a;找到提供程序[org.apache.logging.slf4j. net]。 SLF4J(W)&#xff1a;找到提供程序[ch.qos.log .classi…

【PGCCC】Postgresql Toast 原理

前言 上篇博客讲述了 postgresql 如何存储变长数据&#xff0c;它的应用主要是在 toast 。Toast 在存储大型数据时&#xff0c;会将它存储在单独的表中&#xff08;称为 toast 表&#xff09;。因为 postgresql 的 tuple&#xff08;行数据&#xff09;是存在在 Page 中的&…

C指针创建三维数组

定义的时候变量的位置就是最后一个星号的位置 int*** matrix3d_int(int nz, int nrh, int nch) {int*** matrix (int***)malloc(nz * sizeof(int**));for (int z 0; z < nz; z) {matrix[z] (int**)malloc(nrh * sizeof(int*));for (int y 0; y < nrh; y) {matrix[z][…

window下安装rust 及 vscode配置

安装 安装mingw64 &#xff08;c语言环境 选择posix-ucrt&#xff09; ucrt:通用c运行时库配置mingw64/bin的路径到环境变量中在cmd窗口中输入命令 "gcc -v" 4. 下载Rust安装程序 安装 Rust - Rust 程序设计语言 5. 配置rustup和cargo目录 &#xff08;cargo是包管…

wordpress搭建主题可配置json

网站首页展示 在线访问链接 http://dahua.bloggo.chat/ 配置json文件 我使用的是argon主题&#xff0c;你需要先安装好主题&#xff0c;然后可以导入我的json文件一键配置。 需要json界面配置文件的&#xff0c;可以在评论区回复&#xff0c;看见评论我会私发给你。~

基于表格滚动截屏(表格全部展开,没有滚动条)

import html2canvasPro from html2canvas // 截图&#xff0c;平辅表格 async function resetAgSize() {const allColumns gridApi.value.getColumns()let totalColumnWidth 0let totalColumnHeight 0// 遍历每一个行节点gridApi.value.forEachNode((rowNode) > {totalCo…

运行springBlade项目历程

框架选择 官网地址&#xff1a;https://bladex.cn 使用手册&#xff1a;https://www.kancloud.cn/smallchill/blade 常见问题&#xff1a;https://sns.bladex.cn/article-14966.html 问答社区&#xff1a;https://sns.bladex.cn 环境配置 存在jdk8的情况下安装jdk17 jdk17gi…