基于QT的C++中小项目软件开发架构源码
描述
基于QT信号槽机制实现类之间的交互调用通信,适用于使用不同枚举作为消息交互的类型场景,支持附带任意参数,代码使用方式参考前一篇文章
特性
- 代码简洁,不超过100行
- 仅需包含一个头文件Communicator.h,需要通信的业务类继承
Communicator,界面类继承VCommunicator或MVCommunicator - 消息通过枚举类型定义,支持任意枚举消息,添加枚举无需改动代码。枚举名称区分消息类型,枚举值区分具体消息
- 使用便捷,只需注册消息和消息处理函数
- 提供发送消息时,附带any传递任意额外信息
- 支持多线程,同QT一致的信号槽触发方式,如需控制信号槽触发方式,需要额外补充代码
对比QT信号槽
- 适用于使用不同枚举作为消息类型场景,支持附带任意参数
- 使用同QT一样便捷,只需注册消息和消息回调函数。且如果使用QT的信号槽进行通信,不同的消息的类型则需要定义多个connect连接函数,如ELoginMsg、ERunMsg,多一种消息就要多一个connect
Communicator.h
#pragma once
#include <QMainWindow>
#include <functional>
#include <unordered_map>
#include <any>class MsgHandler {
public:using MsgID = size_t;using MsgHandleFunc = std::function<void(std::any)>;using MsgHandleFuncNoPara = std::function<void()>;template<typename T, typename = std::enable_if_t<std::is_enum<T>::value, void>>void HandleMsg(T msg, std::any info = std::any{}) {m_msgHandlers[HashID(msg)](info);}
protected:template<typename T, typename = std::enable_if_t<std::is_enum<T>::value, void>>MsgID HashID(T msg) {return std::hash<std::string>()(typeid(T).name()) ^ std::hash<size_t>()(static_cast<size_t>(msg));}template<typename T, typename = std::enable_if_t<std::is_enum<T>::value, void>>void RegisterMsgHandler(T msg, MsgHandleFuncNoPara func) {m_msgHandlers.insert({ HashID(msg),[=] (std::any) { func(); } });}template<typename T, typename = std::enable_if_t<std::is_enum<T>::value, void>>void RegisterMsgHandler(T msg, MsgHandleFunc func) {m_msgHandlers.insert({ HashID(msg), func });}template<typename T, typename = std::enable_if_t<std::is_enum<T>::value, void>>void RemoveMsgHandler(T msg) {if (auto findit = m_msgHandlers.find(msg); findit != m_msgHandlers.end()) {m_msgHandlers.erase(findit);}}
protected:std::unordered_map<MsgID, MsgHandleFunc> m_msgHandlers;
};#define DEF_COMMUNICATOR_CLASS(CommClassName, QtClassName) \
class CommClassName : public QtClassName, public MsgHandler { \Q_OBJECT \
public: \CommClassName(QtClassName* parent = nullptr) : QtClassName(parent) { \qRegisterMetaType<MsgID>("MsgID"); \qRegisterMetaType<std::any>("std::any"); \} \Q_SIGNAL void SendMsg(MsgID, std::any); \
public: \Q_SLOT void HandleHashMsg(MsgID msgID, std::any info = std::any{}) { \if (bool findHandler = m_msgHandlers.find(msgID) != m_msgHandlers.end()) { \m_msgHandlers[msgID](info); \} \} \
public: \template<typename Receiver> \void Connect(Receiver* receiver) { \connect(this, &CommClassName::SendMsg, receiver, &Receiver::HandleHashMsg); \} \template<typename Receiver> \void Disconnect(Receiver* receiver) { \disconnect(this, &CommClassName::SendMsg, receiver, &Receiver::HandleHashMsg); \} \
protected: \template<typename T, typename = std::enable_if_t<std::is_enum<T>::value, void>> \void Emit(T msg, std::any info = nullptr) { \emit SendMsg(HashID(msg), info); \} \
}
DEF_COMMUNICATOR_CLASS(Communicator, QObject);
DEF_COMMUNICATOR_CLASS(ViewCommunicator, QWidget);
DEF_COMMUNICATOR_CLASS(MViewCommunicator, QMainWindow);namespace InterConnection {
template<typename Communicator1, typename Communicator2>
void Connect(Communicator1* c1, Communicator2* c2)
{c1->Connect(c2);c2->Connect(c1);
}template<typename Communicator1, typename Communicator2>
void Disconnect(Communicator1* c1, Communicator2* c2)
{c1->Disconnect(c2);c2->Disconnect(c1);
}
}
补充
c++17才支持any,C++17之前的版本可以使用下面的any.h,判断版本大于c++17可以通过宏__cplusplus >= 201703L
any.h
#include <typeinfo>
#include <memory>
namespace std {
class any
{class AnyHelperBase{public:virtual const std::type_info& type()const = 0;virtual AnyHelperBase* clone()const = 0;};template<typename T>class AnyHelper :public AnyHelperBase{public:T data;template<typename ...Args>AnyHelper(Args&&... args) :data(std::forward<Args>(args)...) {}AnyHelper(const AnyHelper& rhs) :data(rhs.data) {}AnyHelper(const T& value) :data(value) {}virtual const std::type_info& type() const{return typeid(T);}virtual AnyHelper* clone() const{return new AnyHelper(*this);}};template<typename T>friend T any_cast(const any& a);
private:std::unique_ptr<AnyHelperBase> pdata{};
public:any() :pdata(nullptr) {}template<typename T>any(T&& value) : pdata(new AnyHelper<std::decay_t<T>>(value)) {}any(const any& rhs) {if (rhs.pdata != nullptr) {pdata.reset(rhs.pdata->clone());}}any(any& rhs) {if (rhs.pdata != nullptr) {pdata.reset(rhs.pdata->clone());}}any(any&& rhs) :pdata(rhs.pdata.release()) {}const std::type_info& type() const{return pdata->type();}bool has_value() const {return pdata != nullptr;}void reset() {pdata.reset();}template<typename T>any& operator=(T value) {pdata.reset(new AnyHelper<std::decay_t<T>>(value));return *this;}any& operator=(any rhs){pdata.reset(rhs.pdata->clone());return *this;}
};template<typename T>
T any_cast(const any& a)
{auto p = dynamic_cast<any::AnyHelper<std::decay_t<T>>*>(a.pdata.get());if (p == nullptr)throw std::runtime_error("Bad any cast!");return p->data;
}
}
由于现在大多软件都是基于QT进行开发,QT又有自己的事件循环机制,所以只能进行拓展通信方式,也可以自行实现事件循环,但是跟QT结合起来用就不太适宜了。
相关文章:
基于QT的C++中小项目软件开发架构源码
描述 基于QT信号槽机制实现类之间的交互调用通信,适用于使用不同枚举作为消息交互的类型场景,支持附带任意参数,代码使用方式参考前一篇文章 特性 代码简洁,不超过100行仅需包含一个头文件Communicator.h,需要通信的…...
self-supervised, weakly supervised, and supervised respectively区别
Self-supervised learning(自监督学习)、weakly supervised learning(弱监督学习)和supervised learning(监督学习)是机器学习中的不同学习范式,它们的主要区别如下: 一、监督学习&…...
安卓好软-----手机屏幕自动点击工具 无需root权限
工具可以设置后自动点击屏幕。可以用于一些操作。例如自动刷视频等等哦 工具介绍 一款可以帮你实现自动操作的软件。软件中你可以根据实际需要设置点击位置,可以是屏幕上的特定位置,也可以是按钮或控件。功能非常强大,但是操作非常简单&…...
【Redis】主从复制(下)--主从复制原理和流程
文章目录 主从复制原理主从节点建立复制流程图数据同步 psyncpsync的语法格式 psync运行流程全量复制全量复制的流程全量复制的缺陷有磁盘复制 vs 无磁盘复制 部分复制部分复制的流程复制积压缓冲区 实时复制 主从复制原理 主从节点建立复制流程图 保存主节点的信息从节点(sla…...
Pencils Protocol上线 Vaults 产品,为 $DAPP 深入赋能
Pencils Protocol 是 Scroll 生态一站式综合收益平台,该平台以 DeFi 功能作为抓手,基于 Farming、Vaults、Auction 等功能不断向 LRT、LaunchPad、AI、FHE、RWA 等领域深入的拓展。 近期 Pencils Protocol 生态不断迎来重磅进展,一个是 $DAPP…...
uni-app+vue3+pina实现全局加载中效果,自定义全局变量和函数可供所有页面使用
首先自定义一个加载中组件 ccloading.vue <template><view class"request-loading-view" v-if"loadingShow"><view class"loading-view"><image class"loading-img" :src"loading" mode"aspectF…...
基于SSM+小程序的在线课堂微信管理系统(在线课堂1)(源码+sql脚本+视频导入教程+文档)
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 &emsp1、管理员实现了首页、个人中心、用户管理、课程分类管理、课程信息管理、课程订阅管理、课程视频管理、公告栏管理、留言板管理、系统管理。 2、用户实现了首页、课程信息、公…...
Uniapp 微信小程序 最新 获取用户头像 和 昵称 方法 有效可用
文章目录 前言代码实现运行效果技术分析 前言 同事有个需求 授权获取用户头像 和 昵称 。之前做过线上小程序发版上线流程 就实现了下 最新的方法和 api 有些变化 记录下 代码实现 先直接上代码 <template><view class"container"><buttonclass&qu…...
儿童手抄报模板-200个(家有神兽必备)
在这个充满色彩与想象的世界里,每一位小朋友都是一位小小艺术家和梦想家。作为家长或老师,我们总是希望能为他们的学习生活增添一抹亮色,激发他们的创造力与探索欲。今天,就为大家带来一份超级实用的资源——儿童手抄报模板-200个…...
动态规划入门题目->使用最小费用爬楼梯
1.题目: 2.解析: 做题模式: 步骤一:找状态转移方程 步骤二:初始化 步三:填表 步骤四:返回-> dp[n] dp[i]表示到达 i 位置最小花费 逻辑:要爬到楼顶先找到 i 位置 , 要…...
中间添加一条可以拖拽的分界线,来动态调整两个模块的宽度
在 React 中操作 DOM 元素时,使用 document.querySelector 以及全局事件监听(如 addEventListener)并不推荐,因为这些方法无法与 React 的生命周期很好地协调,可能会导致内存泄漏或影响性能。 可以改为使用 useRef 和…...
C++的vector优化
1、C中的动态数组一般是特指vector类 2、vector需要优化的原因之一是当我们push_back元素到数组中时,如果原来分配给动态数组的内存不够用了,那么就会找一块更大的内存空间分配给数组,把旧的内容复制到新的内存中去,这就是导致程…...
基于飞腾平台的OpenCV的编译与安装
【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力,聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域,包含了应用使能套件、软件仓库、软件支持、软件适…...
pyside6与协程
目录 一、常见错误 错误一、使用协程函数作为槽函数。 错误二、在Qt循环中创建新的loop 二、解决方法: ①安装库qasync ②修改Qt入口 ③异步槽函数 ④异步函数 ⑤整体示例 一、常见错误 错误一、使用协程函数作为槽函数。 这样是肯定是不行ÿ…...
手机如何五开玩梦幻西游端游?用GameViewer远程手机免费畅玩梦幻西游
用手机就能免费玩梦幻西游端游,还可以随时查看挂机进度! 想要实现这一点,就用网易GameViewer远程,而且不光手机可以玩梦幻西游端游,平板也能免费玩,并为你实现五开玩梦幻西游端游。 那么,通过Ga…...
【笔记】X射线物理基础
一、X射线衍射分析简史 1895年X射线发现 1896 年 2 月对骨折的观察:G.和 E. Frost是第一个使用 X 射线进行医疗用途 1897 年法国海关官员的行李扫描。 X射线衍射理论1 X射线衍射理论2 元素的特征X射线 X射线光电子的应用 电磁波的粒子属性 X射线层析成像法 X-ray…...
Vue3与Flask后端Demo
文章目录 准备工作Flask 后端设置Vue3 前端设置跨域问题测试 准备工作 安装开发环境 安装 Python(推荐 Python 3.8 或更高版本)。安装 Node.js(推荐 LTS 版本)。安装 PyCharm(用于 Flask 开发)和 VSCode&am…...
第一本RAG书籍《大模型RAG实战》出版!
随着ChatGPT的爆火,推动了新一轮的AI技术进步。但大模型自身存在幻觉、知识更新难等问题,阻碍了其直接进行落地应用。RAG(Retrieval-Augmented Generation)技术将LLM与文本信息检索相结合,解决了在一些场景下模型知识不…...
Pandas -----------------------基础知识(四)
自定义函数 Series 加载数据 import pandas as pd df pd.DataFrame({Age: [20, 25, 30, 35, 40]}) df # 目标: 让 Age 列 的每个元素 num1 num2 def add_nums(x,num1,num2):return x num1 num2 df[Age].apply(add_nums,num1 2,num2 3) 法二 df[Age].apply(lambda x ,num1…...
鼎阳加油-IOC关键技术问题的解决记
鼎阳SDS6204示波器EPICS IOC的搭建-CSDN博客 这款示波器在labview下工作的很好,以前搭建逐束团3D系统时连续几个月不间断的工作连接从没断过线,并做过速率测试,单通道时10Hz的波形更新速率都可以达到: 鼎阳SDS6204示波器波形读取…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...
python打卡第47天
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图,展示模…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...
C++ Saucer 编写Windows桌面应用
文章目录 一、背景二、Saucer 简介核心特性典型应用场景 三、生成自己的项目四、以Win32项目方式构建Win32项目禁用最大化按钮 五、总结 一、背景 使用Saucer框架,开发Windows桌面应用,把一个html页面作为GUI设计放到Saucer里,隐藏掉运行时弹…...
