QT上位机开发(会员管理软件)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
前面我们学习了ini文件的解析办法,通过QSettings类就可以很轻松地访问ini文件里面的数据。除了ini文件之外,另外一种经常出现的文件格式其实是json格式。一般来说,如果读写的数据不是很多,那么完全可以用json文件替换成数据库,实现数据的保存和加载工作。今天,我们通过编写一个会员管理软件的办法,正好学习下qt下面如何进行json数据的处理。当然,还可以借助这个小项目,多了解一下qt下面不同控件的用法和写法。
1、设计界面
如果界面上的控件比较少,可以直接用c++语言编写,没有问题。但是如果控件比较多的话,那么建议还是用designer来进行设计。本次编写的会员管理软件,控件的数量稍微有点多,正好可以借这个机会把designer练一练。

练习的过程当中,我们也发现,部分控件存在着排列层次的关系。比如左侧的operation,如果是后面加上去的,没有把它放到单选框、标签、输入框的最下面,那么生成窗口之后,其实不管是radioButton、还是textBox,都是没有办法进行输入的。这一点可能需要稍微注意下。另外,整个界面是删除菜单栏、工具栏和状态栏的。
2、QtWidgetsApplication.h头文件
头文件中需要注意的部分,主要就是各个控件的回调函数。这里面有radioButton的回调函数、按钮的回调函数。其中radioButton虽然是4个,但是可以看成是一组,这样可以少写3个回调函数,编写上面比较方便一点。当然,除了界面之外,关联的业务数据也要根据实际情况及时添加上。
#pragma once#include <string>
#include <vector>
using namespace std;#include <QtWidgets/QMainWindow>
#include "ui_QtWidgetsApplication.h"class QtWidgetsApplication : public QMainWindow
{Q_OBJECTpublic:QtWidgetsApplication(QWidget *parent = nullptr);~QtWidgetsApplication();private:Ui::QtWidgetsApplicationClass ui;int mode_;int max_number_;vector<int> id_array_;vector<string> name_array_;private:int findDataById(int id);void updateData();void loadFile();private:void onRadioButtonToggled(bool checked);void onOkClicked();void onCancelClicked();void onSaveClicked();};
3、QtWidgetsApplication.cpp文件设计
到目前为止,这个cpp文件算得上是目前qt项目代码行数最多的文件,主要也是因为功能要求比较多。首先,它包含了基本的构造函数和析构函数。构造函数里面最主要的部分,就是把控件和它的回调函数关联在一起。其次,代码中涉及到json数据的加载和保存。和c# wpf不同,qt本身有相关的类来处理这些数据。最后,就是业务逻辑。业务逻辑一般比较复杂、麻烦一点,编写之前最好想清楚,比如插入数据的时候是不是需要检查一下是不是有同名id,删除的时候是不是考虑存在找不到的情况。crud的处理方式虽然比较简单,但是涉及到业务层面,还是要想清楚、搞明白,中间出错都没有关系,但是可以通过这个crud来提高自己的业务分析能力,也是不错的一种方式。
另外,因为测试的时候涉及到了data.json文件,这部分大家可以先参考这个模板。将来使用的话,可以在这个模板之上进一步去拓展和延申,
{"count": 6,"items": [{"ID": 1,"NAME": "abcde"},{"ID": 2,"NAME": "bbb"},{"ID": 3,"NAME": "ccc"},{"ID": 5,"NAME": "ddd"},{"ID": 6,"NAME": "eee"},{"ID": 4,"NAME": "fff"}]
}
和ini文件一样,这个json文件也需要保存在h文件、cpp文件目录下面。最后,还是给出完整的cpp代码,虽然内容多了一点,但还是比较有借鉴意义的,可以耐心地去看一看、分析下。
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QJsonArray>
#include <QMessageBox>
#include "QtWidgetsApplication.h"QtWidgetsApplication::QtWidgetsApplication(QWidget *parent): QMainWindow(parent)
{ui.setupUi(this);mode_ = 1; // addmax_number_ = 100; // maximum number is 100ui.radioButton1->setChecked(true); // first radio button is checked right nowloadFile(); // load data from json fileconnect(ui.radioButton1, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);connect(ui.radioButton2, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);connect(ui.radioButton3, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);connect(ui.radioButton4, &QRadioButton::toggled, this, &QtWidgetsApplication::onRadioButtonToggled);connect(ui.pushButton1, &QPushButton::clicked, this, &QtWidgetsApplication::onOkClicked);connect(ui.pushButton2, &QPushButton::clicked, this, &QtWidgetsApplication::onCancelClicked);connect(ui.pushButton3, &QPushButton::clicked, this, &QtWidgetsApplication::onSaveClicked);updateData();
}QtWidgetsApplication::~QtWidgetsApplication()
{}void QtWidgetsApplication::onRadioButtonToggled(bool checked)
{if (checked) {if (sender() == ui.radioButton1){mode_ = 1;ui.lineEdit2->setEnabled(true);}else if (sender() == ui.radioButton2){mode_ = 2;ui.lineEdit2->setEnabled(false);}else if (sender() == ui.radioButton3){mode_ = 3;ui.lineEdit2->setEnabled(true);}else if (sender() == ui.radioButton4){mode_ = 4;ui.lineEdit2->setEnabled(false);}else{qDebug() << "Unknown option was selected";}}
}void QtWidgetsApplication::onOkClicked()
{int id;string name;int pos;bool conversionOK;switch (mode_){case 1: //addif (ui.lineEdit1->text() == ""){QMessageBox::information(nullptr, "Tips", "Id is empty!");return;}if (ui.lineEdit2->text() == ""){QMessageBox::information(nullptr, "Tips", "Name is empty!");return;}if (id_array_.size() >= max_number_){QMessageBox::information(nullptr, "Tips", "Buffer is full!");return;}id = ui.lineEdit1->text().toInt(&conversionOK);if (findDataById(id) != -1){QMessageBox::information(nullptr, "Tips", "Id already existed!");return;}name = ui.lineEdit2->text().toStdString();id_array_.push_back(id);name_array_.push_back(name);QMessageBox::information(nullptr, "Tips", "Successfully add data!");updateData();ui.lineEdit1->setText("");ui.lineEdit2->setText("");break;case 2://delif (ui.lineEdit1->text() == ""){QMessageBox::information(nullptr, "Tips", "Id is empty!");return;}id = ui.lineEdit1->text().toInt(&conversionOK);pos = findDataById(id);if(pos == -1){QMessageBox::information(nullptr, "Tips", "Specified Id does not existed!");return;}id_array_.erase(id_array_.begin() + pos);name_array_.erase(name_array_.begin() + pos);QMessageBox::information(nullptr, "Tips", "Successfully del data!");updateData();ui.lineEdit1->setText("");ui.lineEdit2->setText("");break;case 3:// updateif (ui.lineEdit1->text() == ""){QMessageBox::information(nullptr, "Tips", "Id is empty!");return;}if (ui.lineEdit2->text() == ""){QMessageBox::information(nullptr, "Tips", "Name is empty!");return;}id = ui.lineEdit1->text().toInt(&conversionOK);pos = findDataById(id);if(pos == -1){QMessageBox::information(nullptr, "Tips", "Specified Id does not existed!");return;}name = ui.lineEdit2->text().toStdString();name_array_[pos] = name;QMessageBox::information(nullptr, "Tips", "Successfully update data!");updateData();ui.lineEdit1->setText("");ui.lineEdit2->setText("");break;case 4: // searchif (ui.lineEdit1->text() == ""){QMessageBox::information(nullptr, "Tips", "Id is empty!");return;}id = ui.lineEdit1->text().toInt(&conversionOK);pos = findDataById(id);if (pos == -1){QMessageBox::information(nullptr, "Tips", "Specified Id does not existed!");return;}name = name_array_[pos];ui.lineEdit1->setText("");ui.lineEdit2->setText("");QMessageBox::information(nullptr, "Tips", QString::fromStdString(string("Name is ") + name + string("!")));break;default:break;}
}void QtWidgetsApplication::onCancelClicked()
{this->close();
}void QtWidgetsApplication::onSaveClicked()
{QJsonArray itemsArray;// save data to itemsArrayfor (int i = 0; i < id_array_.size(); i++) {QJsonObject itemObject;itemObject["ID"] = id_array_[i];itemObject["NAME"] = QString::fromStdString(name_array_[i]);itemsArray.append(itemObject);}// create jsonObjectQJsonObject jsonObject;jsonObject["count"] = itemsArray.size();jsonObject["items"] = itemsArray;// transfer to jsonDocuentQJsonDocument jsonDocument(jsonObject);// save to json fileQFile file("data.json");if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {file.write(jsonDocument.toJson());file.close();QMessageBox::information(nullptr, "Tips", "Successfully save the json file!");}else {qDebug() << "Failed to save JSON file";}
}void QtWidgetsApplication::loadFile()
{QFile file("data.json");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {qDebug() << "Failed to open JSON file";return;}QByteArray jsonData = file.readAll();file.close();QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);if (jsonDocument.isNull()) {qDebug() << "Failed to create JSON document";return;}QJsonObject jsonObject = jsonDocument.object();int num = jsonObject["count"].toInt();// get itemsQJsonArray itemsArray = jsonObject["items"].toArray();// read data from itemsfor (int i = 0; i < itemsArray.size(); ++i) {QJsonValue itemValue = itemsArray.at(i);if (itemValue.isObject()) {QJsonObject itemObject = itemValue.toObject();// read dataint id = itemObject["ID"].toInt();QString name = itemObject["NAME"].toString();id_array_.push_back(id);name_array_.push_back(name.toStdString());}}
}int QtWidgetsApplication::findDataById(int id)
{int i;for (i = 0; i < id_array_.size(); i++){if (id_array_[i] == id){return i;}}return -1;
}void QtWidgetsApplication::updateData()
{string s = "";int i;for (i = 0; i < id_array_.size(); i++){s += std::to_string(id_array_[i]);s += " ";s += name_array_[i];s += "\n";}ui.textEdit1->setPlainText("");ui.textEdit1->setPlainText(QString::fromStdString(s));}
4、测试和验证
相比较而言,测试和验证就容易得多。首先,加载的时候,看看json数据有没有全部加载到界界面里面。其次,看下增删改查的功能是否正常。如果一切都没有问题,那就基本ok了。有问题的话,单步去调试即可。

相关文章:
QT上位机开发(会员管理软件)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 前面我们学习了ini文件的解析办法,通过QSettings类就可以很轻松地访问ini文件里面的数据。除了ini文件之外,另外一种经常出…...
线性代数笔记3 1.1
学习视频: 2.2 矩阵运算(二)_哔哩哔哩_bilibili 包括内容: p10矩阵运算(二) p11特殊矩阵 p12逆矩阵(一) p13逆矩阵(二)...
2023年12月编程语言排行榜
TIOBE Index for December 2023 December Headline: C# on its way to become programming language of the year 2023 2023年12月的TIOBE指数:12月头条:c#将成为2023年最佳编程语言 Yes, I know, we have been here before. At the end of 2022, it looked like …...
Redis VS Memcached:选择哪个更适合您的应用?
目录 1、前言 2、概念简介 2.1 Redis 2.2 Memcached 3、数据模型 4、持久性 5、分布式能力 6、性能和扩展性 7、如何选择适合您引用的缓存系统 8、结语 1、前言 Redis和Memcached都是常见的内存缓存系统,用于提升应用程序的性能和可扩展性。它们都具有高…...
【HarmonyOS开发】共享包HAR和HSP的创建和使用以及三方库的发布
OpenHarmony提供了两种共享包,HAR(Harmony Archive)静态共享包,和HSP(Harmony Shared Package)动态共享包。 HAR与HSP都是为了实现代码和资源的共享,都可以包含代码、C库、资源和配置文件&…...
安装 Node.js、npm
安装 nodejs 安装Node.js的最简单的方法是通过软件包管理器。 Node.js官网:https://nodejs.org/en/download/ cd /usr/local/src/wget -c https://nodejs.org/dist/v18.16.0/node-v18.16.0-linux-x64.tar.xz xz -d node-v18.16.0-linux-x64.tar.xz tar -xf node…...
解决报错:找不到显卡
今天做实验碰到一个问题:torch找不到显卡: 打开任务管理器,独显直接没了,一度以为是要去修电脑了,突然想到上次做实验爆显存,屏蔽了gpu用cpu训练: import os os.environ["CUDA_DEVICE_OR…...
如何使用Node.js快速创建本地HTTP服务器并实现公网访问服务端
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
【社交网络分析】课程考试复盘 + 相关资料补充
【社交网络分析】考试后复盘 相关资料补充 写在最前面论述1.描述Logistic回归模型构造损失函数的主要思想。它是如何把线性回归预测模型转化为二分类模型的。Logistic回归模型构造损失函数的主要思想Logistic回归如何将线性回归预测模型转化为二分类模型 2.社交网络分析中面临…...
算法——队列+宽搜(BFS)
队列这种数据结构大都服务于一个算法——宽搜(BFS)。宽搜还可以运用到二叉树、图、迷宫最短路径问题、拓扑排序等等 N叉数的层序遍历 N叉树的层序遍历 题目解析 给定一个 N 叉树,返回其节点值的_层序遍历_。(即从左到右&#…...
前端八股文(CSS篇)二
目录 1.css中可继承与不可继承属性有哪些 2.link和import的区别 3.transition和animation的区别 4.margin和padding的使用场景 5.::before和:after的双冒号和单冒号有什么区别? 6.display:inline-block什么时候会显示间隙 7…...
系统架构设计师笔记
第1章计算机组成与体系结构 1.1.1计算机硬件的组成 (1)控制器。控制器是分析和执行指令的部件,也是统一指挥并控制计算机各部件协调工作的中心部件,所依据的是机器指令。控制器的组成包含如下。 ①程序计数器PC:存储下…...
Livox-Mid-360 固态激光雷达ROS格式数据分析
前言: Livox-Mid-360 官方采用livox_ros_driver2ROS功能包发布ROS格式的数据,livox_ros_driver2可以把Livox原始雷达数据转化成ROS格式并以话题的形式发布出去。 下面列举一些雷达的基本概念: 点云帧:雷达驱动每次向外发送的一…...
如何恢复 iPhone 上永久删除的照片?
2007年,苹果公司推出了一款惊天动地的智能手机,也就是后来的iPhone。你会惊讶地发现,迄今为止,苹果公司已经售出了 7 亿部 iPhone 设备。根据最新一项调查数据,智能手机利润的 95% 都进了苹果公司的腰包。 如此受欢迎…...
基于单片机的公交车站自动报站器设计与实现
一、摘要 随着城市交通的快速发展,公交车作为城市公共交通的主要工具,其便捷性和高效性得到了广泛的认可。然而,由于公交车站的广播系统存在一定的局限性,如人工报站容易出现失误、音量大小不一等问题,给乘客带来了不…...
python之Selenium WebDriver安装与使用
首先把python下载安装后,再添加到环境变量中,再打开控制台输入: pip install selenium 正常情况下是安装好的,检查一下“pip show selenium”命令,出现版本号就说明安装好了。 1:如果出现安装错误: 那就用“…...
基于Java+Vue+uniapp微信小程序国产动漫论坛系统设计和实现
博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容:SpringBoot、Vue、SSM、HLM…...
奇因子之和(C语言)
题意: 一个整数的因子,就是所有可以整除这个数的数。奇数指在整数中,不能被 2 整除的数。所谓整数 Z 的奇因子,就是可以整除 Z 的奇数。 给定 N 个正整数,请你求出它们的第二大奇因子的和。当然,如果该数只…...
简单FTP客户端软件开发——VMware安装Linux虚拟机(命令行版)
VMware安装包和Linux系统镜像: 链接:https://pan.baidu.com/s/1UwF4DT8hNXp_cV0NpSfTww?pwdxnoh 提取码:xnoh 这个学期做计网课程设计【简单FTP客户端软件开发】需要在Linux上配置 ftp服务器,故此用VMware安装了Linux虚拟机&…...
ArkTS开发实践
声明式UI基本概念 应用界面是由一个个页面组成,ArkTS是由ArkUI框架提供,用于以声明式开发范式开发界面的语言。 声明式UI构建页面的过程,其实是组合组件的过程,声明式UI的思想,主要体现在两个方面: 描述…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
