Qt 软件开发框架(详细版)

2023-11-03

该文章用图例+代码方式演示了,一个线上软件基本框架(精简)。开发工具Qt+VS2015

一. 基本要素

这里会用简单的图例和完整代码(这里以Qt代码为例),说明一个线上软件基本的框架。

一个线上windows软件,一般分为几个大的部分

1 UI模块

负责处理来自业务逻辑层或者其它模块的数据展示

2 网络模块

A http、https请求
B websocket(该文章不做赘述)
封装post或get请求,处理请求返回、超时等

3 业务逻辑模块

这里主要处理的是网络模块返回数据的处理,并把结果通知UI模块

4 中间层

负责关联网络模块和业务逻辑模块

5 独立模块(守护进程、更新模块、日志收集模块…)

该文章不做赘述

这里UI模块并非纯UI,其中也有业务逻辑处理。 UI模块和业务逻辑模块 可以做成更低耦合,但是会有降低效率的代价

二. 图例部分

在这里插入图片描述

这里用精简代码演示了
1 从用户操作UI(调用UIMainWnd::sendAsk())
2 发送网络请求(Network::_post(),Network::_get())
3 到请求结果返回(Network::requestFinished())
4 对返回数据处理(BusinessLogicManager::onAskAction())
5 通知UI模块显示(UIMainWnd::on_ask_action())

三. 代码部分

这里使用精简Qt代码演示

1 配置文件模块
#pragma once
/*********************************************************************
*@file       ConfigDef.h
*@brief      管理枚举enum、定义define、QString...
*@author   
*@date       
*********************************************************************/
///@ 网路请求消息结构
typedef struct _tagNetMessage
{
	QString _type;  // 类型
	int  _flag;     // 标识
	QString _url;   // 接口Url
	QString _method;  // 请求方式
	QByteArray _byte; // 参数
}NetMessage;

// 请求接口
/// @brief 发送聊天消息
#define API_POST_ASK_ACTION "http://www.xxxx.com/tztv/ask_action.php"

// 请求类型标识
/// @brief 消息类型(用来在发送和接收网络请求时,区分是哪种消息类型)
namespace RequestType {
#define REQUEST_TYPE_ASK_ACTION "ask_action" // 直播间发送文本消息
};

2 UI模块
// 头文件
/*********************************************************************
*@file       UIMainWnd.h
*@brief      交互界面
*@author      
*@date       
*********************************************************************/
#pragma once
#include <QWidget>

class UIMainWnd : public QWidget
{
	Q_OBJECT

public:
	UIMainWnd(QWidget *parent = Q_NULLPTR);
	~UIMainWnd();
    
    private Q_SLOTS:
	// 文本消息(网络请求返回处理)
    void on_ask_action(bool, const QString&, int _error_code = 0);

private:
	void initUI();
    // 发送文本消息(网络请求)
	void sendText(const QString&_text);
};
// 源文件
UIMainWnd::UIMainWnd(QWidget *parent)
	: QWidget(parent)
{
	initUI();
}

UIMainWnd::~UIMainWnd()
{
}

void UIMainWnd::initUI()
{
    connect(BridgeManager::instance().businessIns(), &BusinessLogicManager::sigAskAction, this, &UIDiscuss::on_ask_action);
}

/**
* 发送文本消息
*/
void UIMainWnd::sendText(const QString&_text)
{
	QByteArray data;
	data.append("channel=" + DataMgr::instance().getLocalUserInfo()._user_group);

	std::string str = Utils::_urlencode(_text.toStdString());
	QString msg_param = QString::fromStdString(str);

	data.append("&message=" + msg_param);
	data.append("&client_type=client");

	NetMessage msg;
	msg._type = REQUEST_TYPE_ASK_ACTION;
	msg._flag = rt_ask_action;
	msg._url = API_POST_ASK_ACTION;
	msg._method = "post";
	msg._byte = data;

	BridgeManager::instance().businessIns()->networkRequest(msg);
}

// 文本消息
void UIMainWnd::on_ask_action(bool bsuccess, const QString&_content, int _error_code)
{
    // 处理来自业务逻辑层的消息
	if (bsuccess)
	{
	}
	else
	{
	}
}
2 网络模块

分为网络模块和网络管理模块,以及超时处理,cookie处理
1)网络模块和超时处理

/*********************************************************************
*@file       Network.h
*@brief      网络模块封装
*@author      
*@date       
*********************************************************************/
#pragma once
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>

class Network : public QObject
{
	Q_OBJECT

public:
	Network(QObject *parent);
	~Network();

	void _get(const QUrl& _url);
	void _post(const QUrl& _url, const QByteArray& _bytes);
	void _setType(const QString& _type,); // 设置该请求的类型RequestType
	void _setCookieJar(QNetworkCookieJar *cookieJar); //设置cookie

Q_SIGNALS:
	// 网络模块->通知网络管理层
    /// 网络请求返回数据
	void sigReply(const QString &_type_net, const QByteArray &_byte_array);
    /// 网络请求失败
	void sigReplyError(const QString &_type_net, const int &_error_code, const QString &_error_string);
    /// 网络请求超时
	void sigTimeout(const QString& _type_net);

	private Q_SLOTS:
    // 对于网络请求返回的处理一般有三种情况:返回成功,返回失败,请求超时
    void requestFinished(QNetworkReply* _reply); // 网络请求返回处理(返回成功、返回失败)
	void on_timeout(); // 超时处理

private:
	QString m_netType = tr(""); // 配置模块中RequestType
	QNetworkRequest m_httpRequest;
	QNetworkAccessManager m_networkAccessManager;
};

// 超时处理
class QReplyTimeout : public QObject 
{
	Q_OBJECT

public:
	QReplyTimeout(QNetworkReply *reply, const int timeout);

signals:
	void sigTimeout();

	private slots:
	void on_timeout();
};
#include "Network.h"

Network::Network(QObject *parent)
	: QObject(parent)
{
	QMetaObject::Connection connRet = QObject::connect(&m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(requestFinished(QNetworkReply*)));
	Q_ASSERT(connRet);
}

Network::~Network()
{
	m_networkAccessManager.disconnect();
}

void Network::_setType(const QString& _type)
{
	m_netType = _type;

}

void Network::_setCookieJar(QNetworkCookieJar *cookieJar)
{
	m_networkAccessManager.setCookieJar(cookieJar);
}

void Network::_get(const QUrl& _url)
{
	m_httpRequest.setUrl(_url);
	QNetworkReply *_reply = m_networkAccessManager.get(m_httpRequest);

	// 请求超时
	QReplyTimeout *pTimeout = new QReplyTimeout(_reply, 5000);
	connect(pTimeout, &QReplyTimeout::sigTimeout, this, &Network::on_timeout);
}

void Network::_post(const QUrl& _url, const QByteArray& _bytes)
{
	QNetworkRequest _request;
	_request.setUrl(_url);

	QNetworkReply *_reply = m_networkAccessManager.post(_request, _bytes);

	// 请求超时
	QReplyTimeout *pTimeout = new QReplyTimeout(_reply, 5000);
	connect(pTimeout, &QReplyTimeout::sigTimeout, this, &Network::on_timeout);
}

void Network::requestFinished(QNetworkReply* _reply)
{
	if (_reply->error() == QNetworkReply::NoError)
	{// request success
		QByteArray _byteArray = _reply->readAll();
        // 这里是日志,方便在日志文件中查看。关于日志生成的看后续文章
		QString _str_error = QString("%1 : request_reply_source_data = %2").arg(m_netType).arg(QString(_byteArray));
		LINFO(L"%s", _str_error.toStdWString().c_str());

		emit sigReply(m_netType, _byteArray);
	}
	else
	{// request fail
		int _error_code = _reply->error();
		QString _log_error = QString("%1 : request_reply_network_error_code = %2").arg(m_netType).arg(QString::number(_error_code));
		LINFO(L"%s", _log_error.toStdWString().c_str());

		QString _error_str = _reply->errorString();
		emit sigReplyError(m_netType, _error_code, _error_str);
	}
	_reply->deleteLater();
}

void Network::on_timeout()
{// request timeout
	QNetworkReply* _reply = (QNetworkReply*)sender();
	int _error_code = _reply->error();

	QString _log_error = QString("%1 : request_reply_timeout = %2").arg(m_netType).arg(QString::number(_error_code));
	LINFO(L"%s", _log_error.toStdWString().c_str());

	emit sigTimeout(m_netType);
}

QReplyTimeout::QReplyTimeout(QNetworkReply *reply, const int timeout)
	: QObject(reply)
{
	Q_ASSERT(reply);
	if (reply && reply->isRunning()) {  // 启动单次定时器
		QTimer::singleShot(timeout, this, SLOT(on_timeout()));
	}
}

void QReplyTimeout::on_timeout()
{  // 处理超时
	QNetworkReply *reply = static_cast<QNetworkReply*>(parent());
	if (reply->isRunning()) {
		reply->abort();
		reply->deleteLater();

		emit sigTimeout();
	}
}

2)网络管理模块

#pragma once
/*********************************************************************
*@file       NetWorkManager.h
*@brief      网络管理层(接收来自业务层请求,把请求结果返回业务层,通过中间层关联)
*@author   
*@date       
*********************************************************************/
#include <QObject>

class NetworkManager : public QObject
{
	Q_OBJECT

public:
	NetworkManager(QObject *parent);
	~NetworkManager();

Q_SIGNALS:
	/// @网络层->业务层(网络层通知业务层)
	void sigReply(const QString& _type, const QByteArray& _byte_array);
	void sigReplyError(const QString &_type_net, const int &_error_code, const QString &_error_string);
	void sigTimeout(const QString& _type_net);

	public Q_SLOTS:
	/// @来自业务层的请求
	void on_net_request_activated(NetMessage &);
};
#include "NetworkManager.h"
#include "Network.h"
#include "NetworkCookie.h"
#include <QNetworkConfiguration>

NetworkManager::NetworkManager(QObject *parent)
	: QObject(parent)
{
	//gu_networkManager->activeConfiguration();
}

NetworkManager::~NetworkManager()
{
}

void NetworkManager::on_net_request_activated(NetMessage &_msg)
{
	Network *_network = new Network(this);
	// 通知业务层
	connect(_network, &Network::sigReply, [this](const QString &_type_net, const QByteArray &_byte_array) {
		emit sigReply(_type_net, _byte_array);
	});
	connect(_network, &Network::sigReplyError, [this](const QString &_type_net, const int &_error_code, const QString &_error_string) {
		emit sigReplyError(_type_net,  _error_code, _error_string);
	});
	connect(_network, &Network::sigTimeout, [this](const QString& _type) {
		emit sigTimeout(_type);
	});

	_network->_setType(_msg._type);
	_network->_setCookieJar(&NetworkCookie::instance());

	// 请求方式
	if (_msg._method == "post")
	{
		_network->_post(_msg._url, _msg._byte);
	}
	else if (_msg._method == "get")
	{
		_network->_get(QUrl(_msg._url));
	}
}

3)cookie处理

#pragma once
/*********************************************************************
*@file        NetworkCookie.h
*@brief      cookie
*@author   
*@date       
*********************************************************************/
#include <QObject>
#include <QtNetwork/QNetworkCookie>  
#include <QtNetwork/QNetworkCookieJar>

class NetworkCookie : public QNetworkCookieJar
{
	Q_OBJECT

public:
	static NetworkCookie& instance();

	QList<QNetworkCookie> getCookies();
	void setCookies(const QList<QNetworkCookie>& cookieList);

private:
	NetworkCookie(QObject *parent);
	~NetworkCookie();
};
#include "NetworkCookie.h"

NetworkCookie::NetworkCookie(QObject *parent)
	: QNetworkCookieJar(parent)
{
}

NetworkCookie::~NetworkCookie()
{
}

NetworkCookie& NetworkCookie::instance()
{
	static NetworkCookie _uniqueInstance(Q_NULLPTR);
	return _uniqueInstance;
}

QList<QNetworkCookie> NetworkCookie::getCookies()
{
	return allCookies();
}

void NetworkCookie::setCookies(const QList<QNetworkCookie>& cookieList)
{
	if (this == NULL)
		return;
	this->setAllCookies(cookieList);
}
3 业务逻辑模块
#pragma once
/*********************************************************************
*@file       BusinessLogicManager.h
*@brief      业务逻辑层
*@author   
*@date       
*********************************************************************/
#include <QObject>
#include <map>
#include <functional>

class BusinessLogicManager : public QObject
{
	Q_OBJECT

public:
	explicit BusinessLogicManager(QObject *parent = nullptr);
	~BusinessLogicManager();

	void networkRequest(NetMessage&);

Q_SIGNALS:
	/// @ 业务层->网络层(UI层通过业务层发送网络请求)
	void sigNetworkRequest(NetMessage&);

	public Q_SLOTS:
    // 网络请求返回成功消息通知
	void on_comming_msg(const QString &_type, const QByteArray&);
    // 网络请求返回失败消息通知
	void on_comming_error(const QString &_type, const int &_error_code, const QString &_error_string);
    // 网络请求超时消息通知
	void on_comming_timeout(const QString &_type);

Q_SIGNALS:
	void sigAskAction(bool, const QString&,  int _error_code = 0);
    
private:
    /// @发送文本消息
    void onAskAction(const QString &_type, const QByteArray& _byte_array);   
}
#include "BusinessLogicManager.h"
#include "NetWorkLayer\NetworkCookie.h"
BusinessLogicManager::BusinessLogicManager(QObject *parent)
	: QObject(parent)
{	
}

BusinessLogicManager::~BusinessLogicManager()
{
}

void BusinessLogicManager::networkRequest(NetMessage&_msg)
{
	emit sigNetRequest(_msg);
}

// 【这里如果请求过多 会出现打来你给ifelse,后续会出关于优化ifelse文章】
void BusinessLogicManager::on_comming_msg(const QString &_type, const QByteArray&_byte)
{
	if (_type == NET_TYPE_ASK_ACTION)
	{// 网络请求成功
		onAskAction(_type, _byte_array);
	}
}

void BusinessLogicManager::on_comming_error(const QString &_type, const int &_error_code, const QString &_error_string)
{
    if (_type == NET_TYPE_ASK_ACTION)
	{// 网络请求错误通知
		emit sigAskAction(false, tr("网络请求错误通知"));
	}
}

void BusinessLogicManager::on_comming_timeout(const QString &_type)
{
    if (_type == NET_TYPE_ASK_ACTION)
	{// 超时处理
		emit sigAskAction(false, tr("超时处理"));
	}
}

/**
* 发送文本消息
*/
void BusinessLogicManager::onAskAction(const QString &_type, const QByteArray& _byte_array)
{
    // 这里是对网络请求返回的数据进行处理,然后通知UI模块
	std::string _f = Jsonc::instance().getJsonValueStringByKey(Utils::byteArray2string(_byte_array), "f");
	QString f = QString::fromStdString(_f);
	QString _context = tr("回复成功");
	if (f == "0")
	{
		_context = tr("回复成功");
		emit sigAskAction(true, tr(""));
	}
	else if (f == "2")
	{
		 _context = tr("未登录");
		emit sigReLogin();
	}
	else if (f == "3")
	{
		_context = tr("字数大于80");
		emit sigAskAction(false, tr("字数大于80"));
	}
	else if (f == "4")
	{
		 _context = tr("内容为空");
		emit sigAskAction(false, tr("内容为空"));
	}
	else if (f == "5")
	{
		_context = tr("3秒后再发言");
		emit sigAskAction(false, tr("3秒后再发言"));
	}
	else if (f == "6")
	{
		_context = tr("您已被禁言");
		emit sigAskAction(false, tr("您已被禁言"));
	}
	else if (f == "7")
	{
		 _context = tr("未绑定手机号");
		emit sigAskAction(false, tr("未绑定手机号"));
	}
}
4 中间层
#pragma once
/*********************************************************************
*@file        BridgeManager.h
*@brief      中间控制层(UI、业务逻辑、网络)
*@author  
*@date       
*********************************************************************/
#include <QObject>
#include "NetWorkLayer\NetworkManager.h"
#include "BusinessLogicLayer\BusinessLogicManager.h"

class BridgeManager : public QObject
{
	Q_OBJECT

public:
	static BridgeManager& instance();

	// 得到网络层 和 业务逻辑层 实例
	BusinessLogicManager* businessIns()const;
	NetworkManager* networkIns()const;

private:
	BridgeManager(QObject *parent);
	~BridgeManager();

private:
	NetworkManager *m_networkManager = nullptr;
	BusinessLogicManager *m_businessLogicManager = nullptr;
};
#include "BridgeManager.h"

BridgeManager::BridgeManager(QObject *parent)
	: QObject(parent)
{
	m_businessLogicManager = new BusinessLogicManager(this);
	m_networkManager = new NetworkManager(this);//这里的实例化得注意了(this 会导致NetWork崩溃)

	// 业务层->网络层
	connect(m_businessLogicManager, &BusinessLogicManager::sigNetworkRequest, m_networkManager, &NetworkManager::on_net_request_activated);

	// 网络层->业务层
	connect(m_networkManager, &NetworkManager::sigReply, m_businessLogicManager, &BusinessLogicManager::on_comming_msg);
	connect(m_networkManager, &NetworkManager::sigReplyError, m_businessLogicManager, &BusinessLogicManager::on_comming_error);
	connect(m_networkManager, &NetworkManager::sigTimeout, m_businessLogicManager, &BusinessLogicManager::on_comming_timeout);
}

BridgeManager::~BridgeManager()
{
}

BridgeManager& BridgeManager::instance()
{
	static BridgeManager _uniqueInstance(Q_NULLPTR);
	return _uniqueInstance;
}

BusinessLogicManager* BridgeManager::businessIns()const
{
	return m_businessLogicManager;
}

NetworkManager* BridgeManager::networkIns()const
{
	return m_networkManager;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt 软件开发框架(详细版) 的相关文章

随机推荐

  • 华为OD机试 - 消消乐游戏(Java)

    题目描述 游戏规则 输入一个只包含英文字母的字符串 字符串中的两个字母如果相邻且相同 就可以消除 在字符串上反复执行消除的动作 直到无法继续消除为止 此时游戏结束 输出最终得到的字符串长度 输入描述 输入原始字符串 str 只能包含大小写英
  • python音频分析工具_python – 鸟鸣音频分析 – 查找两个剪辑的匹配程度

    要做出这个答案 因为评论太久了 我基本上在这个领域工作 所以我觉得我有一些知识 显然 从我的立场来看 我建议使用音频而不是图像 我还建议使用MFCC作为特征提取 您可以将其视为总结 表征音频特定子带的系数 因为它们 GMM是去的 要执行此任
  • SSM入门—SpringMVC框架

    1 SpringMVC概述 Spring Web MVC 是一种基于Java的实现Web MVC设计模式的请求驱动类型的轻量级Web框架 2 MVC的设计模式 M model 模型 业务模型 数据模型 实体 业务代码 数据代码 V View
  • websocket(一)--握手

    最近在琢磨怎么实现服务端的消息推送 因为以前都是通过客户端请求来获取信息的 如果需要实时信息就得轮询 比如通过ajax不停的请求 websocket相当于对HTTP协议进行了升级 客户端和服务端通过websocket协议握手成功后 两者之间
  • 动态内存管理—(malloc、calloc、realloc、free)及常见使用错误

    目录 存在动态内存分配的意义 动态内存函数的介绍 malloc和free calloc realloc realloc在调整内存空间的是存在两种情况 由于上述的两种情况 realloc函数的使用就要注意一些 补充一点 常见的动态内存错误 对
  • 关于Q格式数据总结

    Q格式表示为 Qm n 表示数据用m比特表示整数部分 n比特表示小数部分 共需要 m n 1位来表示这个数据 多余的一位用作符合位 假设小数点在 n位的左边 从右向左数 从而确定小数的精度 例如Q15表示小数部分有15位 一个short 型
  • 为什么有些人年纪轻轻就赚到了很多钱?富人的底层逻辑是什么?

    在 史记 司马迁的书中 除开项羽本纪 秦始皇本纪 高祖本纪英雄的叙述以外 还有一个十分关键的章节目录 那便是 货殖列传 这一章节 十分详尽的纪录那时候商业服务 经济发展 买卖的状况 也体现了司马迁对财富和化学物质的观点 简言之 便是一部有关
  • 安全服务工程师面试题

    文章目录 你如何保护系统和网络免受恶意攻击 你会使用哪些工具和技术 你对密码安全有什么了解 你如何确保用户密码的安全 你如何保护敏感数据和机密信息的安全性 你会使用哪些技术 你如何识别和应对网络威胁 你使用哪些工具和技术 你如何进行网络安全
  • 运行应用程序,提示无法正常启动(0xc000007b)的解决办法

    本文转载自VBcom大牛的博客 感谢VBcom 最后更新 2019 2 28 如图 0xc000007b这个错误使无数玩家烦恼 问题描述 出现这个错误 可能是硬件的问题 也可能是软件的问题 但是 由于硬件引起该问题的概率很小 并且除了更换硬
  • Linux Kernel 编译流程 (一)

    1 config 文件产生 研究Linux Kernel config文件的产生 添加自己的配置 Linux Kernel 4 18 20 Source Insight 3 5 Ubuntu 18 04 arm linux gnueabi
  • FIFO的使用攻略(一看就会)

    一 IP核的方式 1 打开IP核 含义 FIFO是一个先进先出的存储队列 与其他RAM不同的是FIFO没有地址 先入先出 作用 作用就是作为数据的队列通道 让数据暂时缓存 以等待读取 用于异步FIFO模块来实现接口 接口双方都在自己的时钟下
  • WEB安全系列之如何挖掘任意文件读取漏洞

    0x01 前言 任意文件读取漏洞 从代码审计的角度讲一讲 0x02 什么是任意文件下载漏洞 一般的网站都提供读取文件功能 常规的思路是使用一个动态页面 php jsp aspx asp等 将待下载文件作为参数一般参数名称为filename
  • Android面试必备!爆火超全的《Android性能优化全方面解析》

    一 前言 使用过Android系统手机的同学都知道 Android手机越用越卡 这个卡主要体现在手机系统越用越卡 打开APP的速度越来越慢 Android手机越用越卡的原因主要有 1 Android系统源码是开放的 像国内的几大手机厂商 都
  • 【数学建模】常用基本模型总结

    1 线性规划 Linear Programming 运筹学的一个重要分支 数学规划 线性规划是在一组线性约束条件的限制下 求一线性目标函数最大或最小的问题 概念 可行解 最优解 可行域 Matlab中求解线性规划的命令为如下 x返回决策向量
  • 宝塔Linux面板版本免费、专业和企业区别对比选择攻略

    宝塔Linux面板分为免费版 专业版 企业版和企业运维托管版 有必要购买专业版或企业版吗 宝塔Linux面板专业版 企业版和免费版有什么区别 使用免费版的Linux面板商用吗 新手站长来详细说下宝塔Linux面板免费版 专业版 企业版 企业
  • Magisk模块开发指南

    BusyBox Magisk整合了功能完整的BusyBox二进制文件 包括对SELinux的完整支持 执行文件位于 data adb magisk busybox Magisk的BusyBox支持运行时可切换的 ASH Standalone
  • ffmpeg基础五:单独解码裸流aac或MP3或H264

    av parse parse2 用于从输入的数据流中将流中的压缩编码数据一帧一帧的分离出来 也就是从一端数据码流中将需要解码的packet读取出来 由于H264由特殊的格式组成 StartCode NALU Header NALU Payl
  • Python - 实现logging根据日志级别输出不同颜色

    文章目录 一 完整代码 二 代码解释 三 附 自定义颜色对应代码 前段时间因为工作需要脚本打印不同颜色的日志 查找了网上的一些方法 大部分都需要再安装第三方模块 后来选择采用比较简易的办法 类似于print 函数自定义内容颜色 这种方式的缺
  • 14、mysql底层知识进阶-MySql中常用工具:mysqladmin、mysqlbinlog、mysqldump、mysqlimport、mysqlshow

    目录 1 MySql中常用工具 1 1 mysql 1 1 1 连接选项 1 1 2 执行选项 1 2 mysqladmin 1 3 mysqlbinlog 1 4 mysqldump 1 5 mysqlimport source 1 6
  • Qt 软件开发框架(详细版)

    该文章用图例 代码方式演示了 一个线上软件基本框架 精简 开发工具Qt VS2015 一 基本要素 这里会用简单的图例和完整代码 这里以Qt代码为例 说明一个线上软件基本的框架 一个线上windows软件 一般分为几个大的部分 1 UI模块